如何在Haskell中使用Monad类的多个构造函数参数上映射函数?

问题描述 投票:3回答:2

我偶然发现的问题与>>=应用程序有关的样本类型有关:

data ThreeArgs a = ThreeArgs a a a deriving (Show,Eq)

instance Functor ThreeArgs where
    fmap f (ThreeArgs a b c) = ThreeArgs (f a) (f b) (f c)

instance Applicative ThreeArgs where
    pure x = ThreeArgs x x x
    (ThreeArgs a b c) <*> (ThreeArgs p s q) = ThreeArgs (a p) (b s) (c q)

我将声明Monad实例如下:

instance Monad ThreeArgs where
    return x = ThreeArgs x x x
    (ThreeArgs a b c) >>= f = f ... -- a code I need to complete

是,看起来f似乎将应用于所有三个ThreeArgs构造函数自变量。如果我完成最后一行

(ThreeArgs a b c) >>= f = f a

然后编译器没有任何抱怨,而结果是:

*module1> let x = do { x <- ThreeArgs 1 2 3; y <- ThreeArgs 4 6 7; return $ x + y }
*module1> x
ThreeArgs 5 5 5 

这意味着求和结果将进入具有相同参数值的上下文,尽管正确的输出应为ThreeArgs 5 8 10。一旦我编辑到

(ThreeArgs a b c) >>= f = (f a) (f b) (f c)

编译器警报:

 Couldn't match expected type `ThreeArgs b
                                -> ThreeArgs b -> ThreeArgs b -> ThreeArgs b'
              with actual type `ThreeArgs b'

因此,我看到一个严重的错误引导着我的理解,但是我仍然很难理解单子类以及Haskell中的另一类东西。想必我要在这里使用递归还是其他?

haskell functional-programming monads
2个回答
2
投票

ThreeArgs((->) Ordering)同构。证人:

to :: ThreeArgs a -> Ordering -> a
to (ThreeArgs x _ _) LT = x
to (ThreeArgs _ y _) EQ = y
to (ThreeArgs _ _ z) GT = z

from :: (Ordering -> a) -> ThreeArgs a
from f = ThreeArgs (f LT) (f EQ) (f GT)

您的FunctorApplicative实例与((->) r)的实例匹配,因此我们只需使其与its Monad one的实例也匹配,就可以完成。

Monad

顺便说一下,如果想要查找更多有关此数据结构的通用术语,例如instance Monad ThreeArgs where ThreeArgs x y z >>= f = ThreeArgs x' y' z' where ThreeArgs x' _ _ = f x ThreeArgs _ y' _ = f y ThreeArgs _ _ z' = f z ,则为“ representable functor”。


2
投票

这看起来像是ThreeArgs但不是Applicative的示例。请注意,它与标准Monad类型有点类似,只不过它限于固定大小3的列表。如果查看ZipList,您会发现ZipList documentation有一个ZipList实例,但没有ZipList ]实例。

底线:并非所有事物都是单子。这就是我们拥有应用程序的原因之一-有些有用的对象是应用程序,但不是monad。

© www.soinside.com 2019 - 2024. All rights reserved.