【问题标题】:How does this weird monad bind work?这个奇怪的单子绑定是如何工作的?
【发布时间】:2017-11-27 14:56:29
【问题描述】:

这可能是一个非常菜鸟的问题,但我正在玩 Haskell 中的绑定运算符,我遇到了一种使用它重复字符串的方法。

[1..3] >>= const "Hey"
-- Yields "HeyHeyHey"
[1..3] >>= return "Hey"
-- Also yields the same result

我了解>>= (\_ -> return "Hey") 将如何产生["Hey", "Hey", "Hey"],但我不明白为什么(\_ -> "Hey") 重复字符串或为什么>>= return "Hey" 做同样的事情。

【问题讨论】:

    标签: list haskell return bind monads


    【解决方案1】:

    我了解>>= (\_ -> return "Hey") 将如何产生["Hey", "Hey", "Hey"]

    对。 return "Hey" 在这种情况下与 ["Hey"] 相同,因为

    instance Monad [] where
      return x = [x]
    

    所以

    ([1..3] >>= \_ -> return "Hey")
      ≡  ([1..3] >>= \_ -> ["Hey"])
      ≡  ["Hey"] ++ ["Hey"] ++ ["Hey"]
      ≡  ["Hey", "Hey", "Hey"]
    

    现在,>>= (\_ -> "Hey") 也可以用 lambda 中的 list-result 来编写,因为字符串只是字符列表。

    ([1..3] >>= \_ -> "Hey")
      ≡  ([1..3] >>= \_ -> ['H','e','y'])
      ≡  ['H','e','y'] ++ ['H','e','y'] ++ ['H','e','y']
      ≡  ['H','e','y','H','e','y','H','e','y']
      ≡  "HeyHeyHey"
    

    至于>>= return "Hey",那是另一种野兽。 return 在这里属于一个完全不同的 monad,即 function functor

    instance Monad (x->) where
      return y = const y
    

    因此很明显([1..3] >>= const "Hey")([1..3] >>= return "Hey") 给出相同的结果:在该示例中,return 只是const 的另一个名称!

    【讨论】:

    • 我一直很好奇如何查看任何给定的haskell表达式(例如[1..3] >> return "Hey")并知道特定函数(例如return)正在使用哪个实现——我怎么知道函数在这种情况下使用了 Functor 的 return
    • @naomik - 查看类型。从[1..3]我们知道>>=的左侧是Num a => [a]类型,也就是说>>=是在instance Monad []中定义的,它的右侧必须是Num a => a -> [b]类型.我们已经知道return "Hey" :: Monad m => m String,所以现在我们可以声明m String ~ a -> [b],如果我们取b ~ Charm ~ (->) a,我们可以匹配,所以return必须由instance Monad ((->) a)定义。
    • @rampion 当我开始理解时,我的脸上露出了笑容。我还有两个问题 – 1) 我怎样才能准确地解释(例如)m String ~ a -> [b] 中的~?和 2) 多个 return 实现是否有可能满足所需的类型?
    • 1) ~ 是类型级别的相等。你会在我给出的手动类型推理证明和类型约束中看到它(例如(Show a, Monad m, m a ~ String))。 2) 在这个具体的例子中,不,因为我们将m 缩小为Num a => (->) a 并且instance Monad ((->) a) 不依赖于a。如果有单独的 instance Monad ((->) Intinstance Monad ((->) Float) 相反,那将是一个不同的答案。两者都会匹配。
    • @rampion 谢谢你的帮助——你完成了thrill digger assistant 的工作吗?这种类型的问题对我来说很有趣,如果它是开源的,我想看看你的工作^_^
    【解决方案2】:

    这里使用的return 不是用于列表monad,而是用于函数monad,该定义在其中成立:

    return x = \_ -> x
    

    所以这与:

    [1,2,3] >>= (\_ -> "Hey")
    

    由于(>>=) 与列表的concatMap 相同,因此我们有:

    concatMap (\_ -> "Hey") [1,2,3]
    

    你知道为什么这会产生"HeyHeyHey"吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 2022-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多