在Haskell中定义monad

b09cbbtk  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(81)

我目前正在阅读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

但它不会编译并输出
主。hs:22:10:·类型同义词“C”应该有1个参数,但没有给出任何参数
我无法解释。这是怎么回事?* (我做了一些范畴理论,但我刚刚开始学习Haskell)。

wyyhbhjk

wyyhbhjk1#

正如注解中所指出的,您需要一个newtypetype别名只是为了方便程序员,并不是不同的实体,而你想要实现一个类型类,所以你需要一个不同的实体。你可以这样写newtype

newtype C a = C (forall z . (a -> Maybe z) -> Maybe z)

尽管如此,我还是建议包括一个访问器,因为我们稍后将需要它来进行封送处理。

newtype C a = C { unC :: forall z . (a -> Maybe z) -> Maybe z }

(If如果你在家里沿着,你需要{-# LANGUAGE RankNTypes #-}来实现这个forall语法。这是一个编译器扩展,使特定的爱好者类型)
需要明确的是,我们不会为forall z. (a -> Maybe z) -> Maybe z编写Monad示例。那种人不属于我们我们将为C a编写一个Monad示例,C a是我们刚刚创建的一个新类型,它 * 恰好 * 以一种很好的方式与forall z. (a -> Maybe z) -> Maybe z同构。
现在Monad依赖于FunctorApplicative,所以我们从这里开始。
Functorderive-able,所以我们可以只写deriving (Functor),但知道如何写出这些也是很好的实践。

instance Functor C where
    fmap f (C a) = C $ \k -> a (k . f)

现在是Applicative根据相应的Monad示例来实现Applicative是非常常见的,所以我们在这里就这样做。

instance Applicative C where
    pure = return
    (<*>) = ap

(Note:ap来自Control.Monad模块,因此您也需要导入该模块)
只要您编写Monad示例时不调用pure<*>,这种方法就始终有效。
现在是Monad。它与您所写的几乎完全一样,除了一些CunC封送处理以使类型检查器满意。

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)

现在,C Maybe与您刚刚使用的C类型相同,但我们可以将* -> *类型的任何东西替换为m。* 任何东西 *,不仅仅是Functor s。狂野一点

cwxwcias

cwxwcias2#

不能使用部分应用于示例的类型别名。在这种情况下,通常使用newtype来创建一个新类型,但本质上只是它 Package 的类型:

{-# 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构造函数中执行了一些 Package 和解 Package 操作,但这些操作本质上是无操作的。

相关问题