提问人:Julia 提问时间:8/30/2023 更新时间:8/30/2023 访问量:104
在 Haskell 中定义 monad
Defining a monad in Haskell
问:
我目前正在阅读 Kan Extensions for Program Optimisation,在论文的第一页,作者定义了给定 M 一个单子,即以下单子
type C a = ∀z . (a → M z ) → M z
instance Monad C where
return a = λc → c a
m >>= k = λc → m (λa → k a c)
所以我尝试使用 M=Maybe 来玩一下它,因此编写了以下代码
type C a = forall z . (a -> Maybe z) -> Maybe z
instance Monad C where
return a = \c -> c a
m >>= k = \c -> m $ \a -> k a c
但它不编译和输出
Main.hs:22:10:错误: • 类型同义词“C”应该有 1 个参数,但没有得到任何参数
我无法解释。这里有什么问题?(我做过一些范畴理论,但我才刚刚开始学习Haskell)。
答:
如评论中所述,您需要一个 . 别名只是程序员的便利,不是不同的实体,你想要实现一个类型类,所以你需要一个不同的实体。你可以这样写。newtype
type
newtype
newtype C a = C (forall z . (a -> Maybe z) -> Maybe z)
虽然我建议包含一个访问器,因为我们稍后会需要它进行封送。
newtype C a = C { unC :: forall z . (a -> Maybe z) -> Maybe z }
(如果你在家里跟着做,你需要能够执行这个语法。它是一个编译器扩展,支持该特定的更高级类型){-# LANGUAGE RankNTypes #-}
forall
需要明确的是,我们不会为 编写实例。这种类型不属于我们。我们将为 ,为我们刚刚编造的一个新类型编写一个实例,它恰好以一种很好的方式同构。Monad
forall z. (a -> Maybe z) -> Maybe z
Monad
C a
forall z. (a -> Maybe z) -> Maybe z
现在 Monad
依赖于 Functor
和 Applicative
,所以我们将从那里开始。
Functor
是可派生的,所以我们可以直接写,但知道如何写出这些也是很好的做法。deriving (Functor)
instance Functor C where
fmap f (C a) = C $ \k -> a (k . f)
现在。根据相应的实例实现是很常见的,因此我们将在这里执行此操作。Applicative
Applicative
Monad
instance Applicative C where
pure = return
(<*>) = ap
(注意:来自模块,所以你也要导入它)ap
Control.Monad
这始终有效,前提是您编写实例时不调用 或 .Monad
pure
<*>
现在 .它几乎与您编写的内容完全相同,除了一些和编组以使类型检查器满意。Monad
C
unC
instance Monad C where
return a = C (\c -> c a)
m >>= k = C (\c -> unC m $ \a -> unC (k a) c)
最后,请注意,我们从未在这里实际使用过它的任何属性。我们不仅不在乎那是什么,我们甚至不需要它成为.因此,我们也可以通过它进行参数化。Maybe
M
Functor
{-# LANGUAGE RankNTypes #-}
import Control.Monad
newtype C m a = C { unC :: forall z . (a -> m z) -> m z }
instance Functor (C m) where
fmap f (C a) = C $ \k -> a (k . f)
instance Applicative (C m) where
pure = return
(<*>) = ap
instance Monad (C m) where
return a = C (\c -> c a)
m >>= k = C (\c -> unC m $ \a -> unC (k a) c)
Now 与您刚才使用的类型相同,但我们可以用任何种类来代替 .任何事情,而不仅仅是 s. 狂野。C Maybe
C
* -> *
m
Functor
您不能使用部分应用于实例的类型别名。在这种情况下,通常要做的是使用 a 创建一个新类型,但本质上只是它包装的类型:newtype
{-# LANGUAGE RankNTypes #-}
{-# Language UnicodeSyntax #-}
newtype C m a = C { getC :: ∀z . (a → m z ) → m z}
然后将实例定义为:
instance Monad m => Monad (C m) where
return a = C (\c -> c a)
C m >>= k = C (\c -> m (\a -> getC (k a) c))
因此,它在构造函数中进行了一些包装和解包,但这些本质上是无操作的。C
评论
newtype
type
newtype
newtype
data
type
type
newtype
UnicodeSyntax
λ