An open API service indexing awesome lists of open source software.

https://github.com/ennocramer/monad-dijkstra

Haskell monad transformer for weighted, non-deterministic computation
https://github.com/ennocramer/monad-dijkstra

Last synced: 8 months ago
JSON representation

Haskell monad transformer for weighted, non-deterministic computation

Awesome Lists containing this project

README

          

# monad-dijkstra

[![Hackage][hackage-image]][hackage-url]
[![Build Status][ci-image]][ci-url]
[![License][license-image]][license-url]

A monad transformer for weighted graph searches using Dijkstra's or A*
algorithm.

## The SearchT Monad Transformer

This library implements the `SearchT` monad transformer, in which
monadic computations can be associated with costs and alternative
computational paths can be explored concurrently. The API is built in
terms of the `Alternative` and `MonadPlus` type classes and a `cost`
function.

The `runSearch` function lazily evaluates all alternative
computations, returning non-empty solutions in order of increasing
cost. When forcing only the head of the result list, the function
performs the minimal amount of work necessary to guarantee the optimal
solution, i.e. with the least cost, is returned first.

The `runSearchT` function will also evaluate all alternatice
computations in order of increasing cost, but the resulting list will
likely not be lazy, depending bind operation of the underlying monad.
The `collapse` function can be used to terminate the search when all
interesting solutions have been found.

## Computational Cost

The cost of a computation is set using the `cost` function. Repeated
calls within a branch of computation will accumulate the cost using
`mappend` from the type's `Monoid` instance. In addition to the
computational cost expended, the `cost` function also accepts a cost
estimate for the rest of computation. Subsequent calls to `cost` will
reset this estimate.

## Limitations

Any type that satisfies the `Monoid` and `Ord` type classes may be
used as a cost values. However, the internal evaluation algorithm
requires that costs not be negative. That is, for any costs `a` and
`b`, `a <> b >= a && a <> b >= b`.

For the `runSearchT` function to generate solutions in the correct
order, estimates must never overestimate the cost of a computation. If
the cost of a branch is over-estimated or a negative cost is applied,
`runSearchT` may return results in the wrong order.

## Usage Example

```haskell
type Location = ...
type Distance = ...

distance :: Location -> Location -> Distance
distance = ...

neighbors :: Location -> [(Location, Distance)]
neighbors = ...

shortedtRoute :: Location -> Location -> Maybe (Distance, [Location])
shortestRoute from to = listToMaybe $ runSearch $ go [from]
where
go ls = if head ls == to
then return ls
else msum $ flip map (neighbors (head ls)) $
\(l, d) -> cost d (distance l to) $ go (l : ls)
```

[hackage-image]: https://img.shields.io/hackage/v/monad-dijkstra.svg?style=flat
[hackage-url]: https://hackage.haskell.org/package/monad-dijkstra
[ci-image]: https://github.com/ennocramer/monad-dijkstra/workflows/CI%20Pipeline/badge.svg
[ci-url]: https://github.com/ennocramer/monad-dijkstra/actions?query=workflow%3A%22CI+Pipeline%22
[license-image]: https://img.shields.io/badge/license-BSD--3--Clause-blue?style=flat-square
[license-url]: https://github.com/ennocramer/monad-dijkstra/blob/master/LICENSE.md