Specializing bind for monads over special typeclasses in Haskell

前端 未结 3 1731
陌清茗
陌清茗 2021-02-06 14:13

In the second last chapter For a Few Monads More of the very nice tutorial \"Learn You a Haskell for a Great Good\" the author defines the following monad:

impor         


        
3条回答
  •  无人及你
    2021-02-06 14:40

    This is called a "restricted monad" and you define it like this:

    {-# LANGUAGE ConstraintKinds, TypeFamilies, KindSignatures, FlexibleContexts, UndecidableInstances #-}
    module Control.Restricted (RFunctor(..),
                               RApplicative(..),
                               RMonad(..),
                               RMonadPlus(..),) where
    import Prelude hiding (Functor(..), Monad(..))
    import Data.Foldable (Foldable(foldMap))
    import GHC.Exts (Constraint)
    
    class RFunctor f where
        type Restriction f a :: Constraint
        fmap :: (Restriction f a, Restriction f b) => (a -> b) -> f a -> f b
    
    class (RFunctor f) => RApplicative f where
        pure :: (Restriction f a) => a -> f a
        (<*>) :: (Restriction f a, Restriction f b) => f (a -> b) -> f a -> f b
    
    class (RApplicative m) => RMonad m where
        (>>=) :: (Restriction m a, Restriction m b) => m a -> (a -> m b) -> m b
        (>>) :: (Restriction m a, Restriction m b)  => m a -> m b ->  m b
        a >> b = a >>= \_ -> b
        join :: (Restriction m a, Restriction m (m a)) => m (m a) -> m a
        join a = a >>= id
        fail :: (Restriction m a) => String -> m a
        fail = error
    
    return :: (RMonad m, Restriction m a) => a -> m a
    return = pure
    
    class (RMonad m) => RMonadPlus m where
        mplus :: (Restriction m a) => m a -> m a -> m a
        mzero :: (Restriction m a) => m a
        msum :: (Restriction m a, Foldable t) => t (m a) -> m a
        msum t = getRMonadPlusMonoid $ foldMap RMonadPlusMonoid t
    
    data RMonadPlusMonoid m a = RMonadPlusMonoid { getRMonadPlusMonoid :: m a }
    
    instance (RMonadPlus m, Restriction m a) => Monoid (RMonadPlusMonoid m a) where
        mappend (RMonadPlusMonoid x) (RMonadPlusMonoid y) = RMonadPlusMonoid $ mplus x y
        mempty = RMonadPlusMonoid mzero
        mconcat t = RMonadPlusMonoid . msum $ map getRMonadPlusMonoid t
    
    guard :: (RMonadPlus m, Restriction m a) => Bool -> m ()
    guard p = if p then return () else mzero
    

    To use a restricted monad, you need to begin your file like this:

    {-# LANGUAGE ConstraintKinds, TypeFamilies, RebindableSyntax #-}
    module {- module line -} where
    import Prelude hiding (Functor(..), Monad(..))
    import Control.Restricted
    

提交回复
热议问题