【问题标题】:Help in understanding pointfree code帮助理解无点代码
【发布时间】:2011-07-22 23:45:40
【问题描述】:

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

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

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

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

【问题讨论】:

  • join :: m (m a) -> m a 并没有完全“移除”一层单子包裹,更准确地说是将两层压缩成一层。因此这个名字,确实......

标签: haskell pointfree


【解决方案1】:

join 将Monad 的实例用于(->) 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)

如您所见,(->) a 的实例使join 成为一个应用两次参数的函数。因此,join (*) 就是 \x -> x * x。

【讨论】:

  • 您也可以从参数化中解决这个问题。在 monad (->) a 中,join 的类型为 ((->) a) ((->) a b) -> ((->) a b),简化为 (a -> a -> b) -> a -> b。很明显,join 要获得b,唯一能做的就是将a 提供给函数两次。 (当然,除了使用底部值)。
  • @hammar 没有一个程序可以通过查看类型签名来找出函数唯一合理的定义吗? (如果可能)
  • @FUZxxl:是的,Djinn。不过,这个包似乎有点过时了。
  • 我上传了新版本的 Djinn。
  • 谢谢,正是我所缺少的! :-) 我实际上玩过((->) a) 的monad 实例,但没有得到任何结果,可能是因为这里接近凌晨2 点,我很累。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
相关资源
最近更新 更多