17

在玩Pointfree时,我看到了一段我似乎无法理解的代码。

:pl map (\x -> x * x) [1..10]
-- map (join (*)) [1..10]

我的主要问题是我不明白join这里的工作方式。我知道它“删除”了一层单子包装(m (m a)to m a)。我认为它归结为类似的东西[1..10] >>= (\x -> [x * x]),但我真的不明白“额外层”是如何引入的。我明白了join x = x >>= id,但是我仍然坚持如何“复制”每个值以便(*)获得两个参数。这已经困扰了我大约半个小时了,我主要是对自己感到恼火,因为我觉得我拥有所有的拼图,但似乎无法将它们组合在一起......

PS 别担心,我不会真正使用这个无点版本,这纯粹是出于好奇,也是为了更好地理解 Haskell。

4

1 回答 1

21

join正在使用Monadfor的实例(->) a,如 中所定义Control.Monad.Instances。该实例类似于Reader,但没有显式包装器。它是这样定义的:

instance Monad ((->) a) where
  -- return :: b -> (a -> b)
  return = const
  -- (>>=) :: (a -> b) -> (b -> a -> c) -> (a -> c)
  f >>= g = \x -> g (f x) x

如果您现在减少join使用此实例:

join
(>>= id)
flip (\f g x -> g (f x) x) (\a -> a)
(\f x -> (\a -> a) (f x) x)
(\f x -> f x x)

如您所见, for 的实例(->) a使join函数应用了两次参数。正因为如此,join (*)简直就是\x -> x * x

于 2011-07-22T23:58:53.450 回答