Skip to content

Instantly share code, notes, and snippets.

View ymdryo's full-sized avatar

Riyo ymdryo

View GitHub Profile

Most Haskell effect libraries including Heftia use integer IDs for so‑called "effect tags" to identify which effect to handle. Concretely, this ID is the index of that effect in a type‑level list representing the effect set. For example, in the set

{Reader[String], Reader[Double], Reader[Char]}

the tag ID of State[Char] is 2.

Effect handling matches on these tag IDs at runtime to determine which effect to interpret. The tag IDs themselves, however, are computed at compile time via type‑level computation.

#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

Generalizing the unwrap/rewrap operation yields the following function:

withLogicToEff :: (forall e. (Logic es a -> Eff (e :& es) ()) -> Eff (e :& es) ()) -> Logic es a
withLogicToEff f = MkLogic \y -> f \m -> enumerate m y

It has a signature similar to MonadUnliftIO's withRunInIO:

#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, pipes
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
import Pipes
import Control.Applicative
#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
import Control.Monad (when)
import Control.Monad.Hefty (Eff, Effect, Emb, FOEs, In, Throw, interpretBy, liftIO, makeEffectF, runEff, (:>))
import Control.Monad.Hefty.Except (catch, runCatch, runThrow, throw'_)
import Data.List (singleton)
data Choice :: Effect where
Empty :: Choice m a
Choice :: Choice m Bool
makeEffectF ''Choice
#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7, unliftio
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
#!/usr/bin/env -S cabal run -v1
{- cabal:
build-depends: base, heftia-effects ^>= 0.7, unliftio
ghc-options: -Wall
-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}