【发布时间】:2014-10-13 01:45:51
【问题描述】:
我正在学习“Learn You a Haskell”,现在正在阅读关于 monad 的章节。在其他与 Haskell 相关的帖子中,我看到很多人推荐 sigfpe 关于 monads 的博文;强烈建议 Haskell 学生通过他/她自己的各种练习来“发明”/“发现”单子的概念。
我在容器练习的最后一步遇到问题。我认为链接到他的网站会违反论坛规则,所以我会尽力在这里描述它。 (如果我在这方面错了,Lmk。)作为提醒,我对练习的描述可能并不完全连贯,因此最好使用简单的谷歌搜索:)
概览:
-
每组练习都会引导读者完成构建不同类型的 monad 的步骤。大致步骤如下:
- 我们考虑两个函数 -
f'和g'- 它们具有相同的类型声明 - 我们构造了一个函数 (
bind),它允许我们组合f和g以使输出有意义(一旦您看到下面的具体练习,可能会更有意义)。直接组合不起作用,因为f和g的返回类型与它们的参数类型不匹配。 - 接下来,我们定义一个恒等函数 (
unit),使得以下为真:(bind unit . f') == (bind f' . unit) - 在上一步的基础上,我们定义了一个
lift函数,使得lift f = unit . f - 在最后一步中,我们被要求证明以下情况成立:
bind (lift f) (lift g) == lift . bind f g
- 我们考虑两个函数 -
这是我正在做的一组练习:
- 我们被要求考虑两个函数
sqrt'和cbrt',它们计算复数的平方根和立方根(即 a + bi 形式的数字,其中 a 和 b 是实数,i 是平方根负一)。基础数学并不重要。重要的是可能的第 n 个根的数量是 n。换句话说,复数(即 a + bi 的形式)具有复数的两个平方根、复数的三个立方根等。 -
鉴于复根的性质,
sqrt'和cbrt'都接受Complex类型的参数并返回[Complex]类型是有意义的。我们被要求构建一个bind函数,它可以让我们计算复数的六次方根,同时利用我们已经拥有 sqrt' 和 cbrt' 的事实。 (直接合成 obv 不起作用)bind :: (Complex -> [Complex) -> [Complex] -> [Complex] bind f = (concat . map f) -
接下来,我们构造
unit和lift:unit :: Complex -> [Complex] unit x = [x]lift :: (Complex -> [Complex]) -> Complex -> [Complex] lift f = unit . f -
在最后一步(这是我遇到的问题),我们被要求显示以下内容:
bind (lift f) (lift g) == lift . bind f g
首先,这个等式的左边不是有一个类型不匹配的lift 不能接受[Complex] 类型的参数吗?退后一步,我不确定我们为什么还要费心定义unit 和lift。 (我天真地认为bind 的定义解决了手头的问题,因此转到下一个问题。)如果有人能帮助我理解为什么我们定义这两个函数然后寻求证明最后一个函数,我将不胜感激平等。
作为参考,下面附上我的代码。请注意,bind、unit 和 lift 函数具有通用类型声明。
bind :: (a1 -> [a]) -> [a1] -> [a]
bind f' = (concat . map f')
unit :: t -> [t]
unit x = [x]
lift :: (a -> b) -> a -> [b]
lift f = unit . f
--Definitions of cbRootC and sqRootC
data Complex = Complex Float Float deriving (Show)
cbrt' = rootC 3
sqrt' = rootC 2
rootC :: Float -> Complex -> [Complex]
rootC n (Complex a b) = zipWith Complex r i
where r = map (* (mod ** (1/n) )) $ map cos $ map arg [0..n-1]
i = map (* (mod ** (1/n) )) $ map sin $ map arg [0..n-1]
arg = ( * (2*pi / n) )
mod = sqrt (a*a + b*b)
【问题讨论】: