Skip to content

Instantly share code, notes, and snippets.

@dmwit
Created June 12, 2021 06:35
Show Gist options
  • Save dmwit/f9dbbbfc37ef5e5ab812d860eed77708 to your computer and use it in GitHub Desktop.
Save dmwit/f9dbbbfc37ef5e5ab812d860eed77708 to your computer and use it in GitHub Desktop.
MonadLogic, but both associations of >>- are productive
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
import Control.Applicative
import Control.Monad
import Data.Maybe
-- explicit failure
newtype EF a = EF { unEF :: [Maybe a] }
deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
instance Applicative EF where
pure = EF . pure . pure
(<*>) = ap
instance Monad EF where
EF xms >>= f = EF
[ fxm
| xm <- xms
, fxm <- case xm of
Nothing -> [Nothing]
Just x -> unEF (f x)
]
instance Alternative EF where
empty = EF [Nothing]
EF xms <|> EF xms' = EF (xms <|> xms')
runEF :: EF a -> [a]
runEF = catMaybes . unEF
interleave :: EF a -> EF a -> EF a
interleave (EF []) m2 = m2
interleave (EF (xm:m1)) m2 = EF (xm : unEF (interleave m2 (EF m1)))
infixl 1 >>-
(>>-) :: EF a -> (a -> EF b) -> EF b
EF [] >>- f = EF []
EF (xm:xms) >>- f = maybe
(EF . (Nothing:) . unEF)
(interleave . f)
xm
(EF xms >>- f)
odds :: EF Integer
odds = pure 1 <|> fmap (2+) odds
oddsPlus :: Integer -> EF Integer
oddsPlus n = odds >>= \a -> pure (a+n)
ensure :: Alternative f => (a -> Bool) -> a -> f a
ensure p x = x <$ guard (p x)
leftAssociated :: [Integer]
leftAssociated = runEF ((pure 0 <|> pure 1) >>- oddsPlus >>- ensure even)
rightAssociated :: [Integer]
rightAssociated = runEF ((pure 0 <|> pure 1) >>- (\a -> oddsPlus a >>- ensure even))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment