定义新的 monad 实例

defining new monad instance

几天前,我试图通过创建一个新的 monad 实例来证明 monad 法则,但我发现自己陷入了定义新 monad 实例的困境。

{-# LANGUAGE DeriveFunctor, InstanceSigs #-}
import Control.Monad

newtype Test a = Test { getTest :: [Maybe a] }
  deriving Functor

instance Applicative Test where
  pure = return
  (<*>) = liftM2 ($)

instance Monad Test where
  return :: a -> Test a
  return a = Test $ [Just a]
  
  (>>=) :: Test a -> (a -> Test b) -> Test b
  g >>= f = concat (map f g)  --Tried to do something like this

我在列表 monad 定义之后尝试了一些东西,但是因为 concat 期望 [[a]] 而卡住了,但在这里它得到了 [Test b],所以也许还有其他可用的函数或者有没有办法让 concat 工作在新类型上?任何建议表示赞赏。谢谢

type 别名不同,newtype 包装器需要手动应用和删除。将 g >>= f = concat (map f g) 替换为 Test g >>= f = Test $ concat (map (getTest . f) g).

这只会给您留下一个类型错误:g 的类型是 [Maybe a] 而不是所需的 [a]。我们可以添加一个 catMaybes(需要 import Data.Maybe)来解决这个问题:Test g >>= f = Test $ concat (map (getTest . f) $ catMaybes g)。现在可以编译了。

不幸的是,这种情况是不合法的。我将把它留作 reader 的练习,以确定为什么不可以,以及它是否可以轻松修复。

它们可以是derived the the MaybeT [] transformer:

{-# Language DerivingVia              #-}
{-# Language StandaloneKindSignatures #-}

import Control.Applicative       (Alternative)
import Control.Monad             (MonadPlus)
import Control.Monad.Fix         (MonadFix)
import Control.Monad.Trans.Maybe (MaybeT(..))
import Control.Monad.Zip         (MonadZip)
import Data.Kind                 (Type)

type    Test :: Type -> Type
newtype Test a = Test { getTest :: [Maybe a] }
 deriving (Functor, Foldable, Applicative, Alternative, Monad, MonadFail, MonadFix, MonadPlus, MonadZip)
 via MaybeT []

:instances MaybeT []:

>> :instances MaybeT []
instance [safe] GHC.Base.Alternative (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Applicative (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Functor (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Monad (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] GHC.Base.MonadPlus (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Data.Functor.Classes.Eq1 (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Foldable (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Data.Functor.Classes.Ord1 (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Data.Functor.Classes.Read1 (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Data.Functor.Classes.Show1 (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Traversable (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] MonadFail (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Control.Monad.Fix.MonadFix (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Control.Monad.Zip.MonadZip (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Monad (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Applicative (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’
instance [safe] Functor (MaybeT [])
  -- Defined in ‘Control.Monad.Trans.Maybe’

其中一些实例也可以通过 Compose [] Maybe but famously monads don't compose. :instances Compose [] Maybe:

派生
>> :instances Compose [] Maybe
instance Alternative (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Applicative (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Functor (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Foldable (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Eq1 (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Ord1 (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Read1 (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Show1 (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Traversable (Compose [] Maybe)
  -- Defined in ‘Data.Functor.Compose’
instance Alt (Compose [] Maybe) -- Defined in ‘Data.Functor.Alt’
instance Hashable1 (Compose [] Maybe)
  -- Defined in ‘hashable-1.3.0.0:Data.Hashable.Class’