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

huangapple go评论88阅读模式
英文:

How to map a function over multiple constructor arguments working with Monad class in Haskell?

问题

以下是您要翻译的内容:

我卡住的问题涉及到像这样对`>>=`应用到一个示例类型的情况:

    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 ... -- 我需要完成的代码

是的,看起来`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)

编译器会警告:

     无法匹配预期类型`ThreeArgs b
                                    -> ThreeArgs b -> ThreeArgs b -> ThreeArgs b'
                  实际类型是`ThreeArgs b'

所以,我看到一个严重的错误指导了我的理解,但对于Haskell中的monadic类和其他类似的东西来说,对我来说仍然相当困难。我可能想在这里使用递归还是其他什么?
英文:

The problem I'm stumbled at has to do with >>= application to a sample type like that:

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)

I'd declare a Monad instance as follows:

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

Yes, it looks as if f to be applied to all three ThreeArgs contructor arguments. If I complete last line

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

then compiler doesn't have any complaints, whereas result is:

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

it means that summation results into a context with same argument values, although correct output should be ThreeArgs 5 8 10. Once I edit to

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

compiler alerts:

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

So, I see a serious mistake guides my comprehension, but it's still rather hard to me to understand monadic class and another such things in Haskell. Presumably, do I want to use recursion here or what else?

答案1

得分: 7

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)的工作方式相匹配,所以我们只需要使其与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

顺便说一下,类似于ThreeArgs这样的数据结构的通用术语是"可表示函子",如果你想查找更多相关信息,可以搜索这个术语。

英文:

ThreeArgs is isomorphic to ((->) Ordering). Witness:

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)

Your Functor and Applicative instances match how the ones for ((->) r) work, so we can just make it match how its Monad one works too and we're done.

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

By the way, the general term for data structures like ThreeArgs is "representable functor", if you want to look up more about this.

huangapple
  • 本文由 发表于 2020年1月6日 02:55:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/59603170.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定