sayo-hs / heftia

higher-order algebraic effects done right for Haskell
Mozilla Public License 2.0
55 stars 2 forks source link

Merge `Fre` into `Hef` #3

Closed ymdryo closed 9 months ago

ymdryo commented 12 months ago

Keeping these as separate data types or interfaces doesn’t seem to be very convenient.

ymdryo commented 11 months ago

new version interface idea

infixr 4 !!
infixr 3 !

-- `Effectful` monads for general purposes.
type (!!) = EffEK :: SigClass -> InsClass -> Type -> Type
type (!) = EffFEK :: InsClass -> Type -> Type

toF :: NopS !! f ~> (!) f
toF = ...

class HeftiaEff (he :: SigClass -> InsClass -> Type -> Type) where ...
class FreerEff (fr :: InsClass -> Type -> Type) where ...

instance (Heftia he, Union uh, UnionF uf) => HeftiaEff (Eff uh uf he)

instance (Heftia he, UnionF uf) => FreerEff (Eff uh uf he NopS)
instance (Freer fr, UnionF u) => FreerEff (EffF u fr)

-- | A common monad wrapper data type for representing effectful programs.
newtype Eff (uh :: [SigClass] -> SigClass) (uf :: [InsClass] -> InsClass) heftia hs fs =
    Eff { unEff :: Effectful heftia (AsUnion uh (SumToList hs)) (AsUnionF uf (SumToListF fs)) }

type EffE = Eff ExtensibleUnion ExtensibleUnionF

type EffEK = EffE HeftiaChurch
type EffETree = EffE HeftiaTree

type Effectful heftia h f = heftia (h :+: LiftIns f) :: Type -> Type
type EffectfulK = Effectful HeftiaChurch
type EffectfulTree = Effectful HeftiaTree

newtype EffF (u :: [InsClass] -> InsClass) freer fs = EffF { unEffF :: freer (AsUnionF u (SumToListF fs)) }
type EffFE = Eff ExtensibleUnionF
type EffFEK = EffFE FreerChurch
type EffFETree = EffFE FreerTree

type InsClass = Type -> Type
type SigClass = (Type -> Type) -> Type -> Type

infixr 5 +, :+:
data f + g = ... -- Functor sum
data h1 :+: h2 = ... -- HFunctor sum

data NopI (a :: Type)
type NopS = LiftIns NopI

data ExtensibleUnionF :: [InsClass] -> InsClass
data ExtensibleUnion :: [SigClass] -> SigClass

-- Enclose the sums as a linear list in the right-associative direction.

type family SumToListF f :: InsClass -> [InsClass] where
    SumToListF (f + g) = f ': SumToListF g
    SumToListF NopI = '[]
    SumToListF f = '[f]

type family SumToList h :: SigClass -> [SigClass] where
    SumToList (h1 :+: h2) = h1 ': SumToList h2
    SumToList NopS = '[]
    SumToList h = '[h]

type family AsUnionF u fs :: ([InsClass] -> InsClass) -> [InsClass] -> InsClass where
    AsUnionF u '[] = NopI
    AsUnionF u '[f] = f
    AsUnionF u fs = u fs

type family AsUnion u hs :: ([SigClass] -> SigClass) -> [SigClass] -> SigClass where
    AsUnion u '[] = NopS
    AsUnion u '[h] = h
    AsUnion u hs = u hs

By using the interface, we can expect to be able to write as follows:

saveLogChunk ::
    forall h f.
    ( LogChunkS <<| h
    , LogI <| f
    , FileSystemI <| f
    , TimeI <| f
    , HFunctor h
    ) =>
    LogChunkS :+: h !! LogI + f ~> h !! LogI + f
teletypeToIO :: IO <| r => (!) (TeletypeS + r) ~> (!) r
or
teletypeToIO :: IO <| r => TeletypeS + r ! a -> r ! a

instead of:

saveLogChunk ::
    forall es es' m.
    ( LogChunkS <<| es
    , LogI <| es'
    , FileSystem (Fre es' m)
    , Time (Fre es' m)
    , Monad m
    , ForallHFunctor es
    ) =>
    Hef (LogChunkS ': es) (Fre (LogI ': es') m) ~> Hef es (Fre (LogI ': es') m)
teletypeToIO :: (IO <: Fre es m, Monad m) => Fre (TeletypeI ': es) m ~> Fre es m

Note that for the paper, the left and right sides of the ! and !! operators are swapped.

ymdryo commented 9 months ago

In the new version of the interface, the fundamental type 'Effectful' representing effectful programs has become a structure that combines both first-order and higher-order effect sets in a sum. This is a merged form of 'Fre' and 'Hef'. https://github.com/sayo-hs/heftia/blob/3bfca50e14ca1eb602015cbe0380afe4483b060f/heftia/src/Control/Effect/Hefty.hs#L52-L65

Additionally, an 'EffectfulF' type that only allows first-order effects has been added. This corresponds to 'Fre' in the older version. https://github.com/sayo-hs/heftia/blob/3bfca50e14ca1eb602015cbe0380afe4483b060f/heftia/src/Control/Effect/Free.hs#L60-L66