我试图理解
的结果(*) . (+)
在 haskell 。我知道复合运算符只是数学函数的标准复合 - 所以
(f . g) = f (g x)
但是:
(*) . (+) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
我正在努力理解这种类型签名。我本来希望能够做这样的事情:
((*) . (+)) 1 2 :: Num a => a -> a
= (* (+ 1 2))
(*) 的含义是什么。 (+) 的类型签名?我尝试通过类似的方式来玩它(只是与它的签名匹配):
((*) . (+)) 1 (\x -> x + 1) 1
但是编译失败。我试图在撰写这些内容时逐步完成逻辑步骤,但我没有完全理解它是如何得到这个结果的(以及结果是什么)。
最佳答案
我理解你的感受。我发现函数组合一开始也很难掌握。帮助我理解这个问题的是类型签名。考虑:
(*) :: Num x => x -> x -> x
(+) :: Num y => y -> y -> y
(.) :: (b -> c) -> (a -> b) -> a -> c
现在当你写(*) . (+)
时它实际上与 (.) (*) (+)
相同(即 (*)
是 (.)
的第一个参数, (+)
是 (.)
的第二个参数):
(.) :: (b -> c) -> (a -> b) -> a -> c
|______| |______|
| |
(*) (+)
因此类型签名为 (*)
(即 Num x => x -> x -> x
)与 b -> c
统一:
(*) :: Num x => x -> x -> x -- remember that `x -> x -> x`
| |____| -- is implicitly `x -> (x -> x)`
| |
b -> c
(.) (*) :: (a -> b) -> a -> c
| |
| |‾‾‾‾|
Num x => x x -> x
(.) (*) :: Num x => (a -> x) -> a -> x -> x
因此类型签名为 (+)
(即 Num y => y -> y -> y
)与 Num x => a -> x
统一:
(+) :: Num y => y -> y -> y -- remember that `y -> y -> y`
| |____| -- is implicitly `y -> (y -> y)`
| |
Num x => a -> x
(.) (*) (+) :: Num x => a -> x -> x
| | |
| |‾‾‾‾| |‾‾‾‾|
Num y => y y -> y y -> y
(.) (*) (+) :: (Num (y -> y), Num y) => y -> (y -> y) -> y -> y
我希望能够澄清 Num (y -> y)
在哪里和Num y
来自。你留下了一个非常奇怪的类型 (Num (y -> y), Num y) => y -> (y -> y) -> y -> y
的函数。 .
让它如此奇怪的是它期望 y
和y -> y
成为 Num
的实例。可以理解的是y
应该是 Num
的一个实例,但是如何y -> y
?制作y -> y
Num
的一个实例似乎不合逻辑。这不可能是正确的。
但是,当您查看函数组合实际执行的操作时,这是有意义的:
( f . g ) = \z -> f ( g z)
((*) . (+)) = \z -> (*) ((+) z)
所以你有一个函数\z -> (*) ((+) z)
。因此z
显然必须是 Num
的实例因为(+)
被应用到它。因此 \z -> (*) ((+) z)
的类型是 Num t => t -> ...
哪里...
类型为(*) ((+) z)
,我们稍后就会知道。
因此((+) z)
类型为Num t => t -> t
因为它还需要一个号码。但是,在将其应用于另一个号码之前,(*)
应用于它。
因此(*)
预计((+) z)
成为 Num
的实例,这就是为什么t -> t
预计是 Num
的实例。因此...
替换为 (t -> t) -> t -> t
和约束 Num (t -> t)
添加后,得到类型 (Num (t -> t), Num t) => t -> (t -> t) -> t -> t
.
您真正想要的组合方式 (*)
和(+)
正在使用(.:)
:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
f .: g = \x y -> f (g x y)
因此(*) .: (+)
与 \x y -> (*) ((+) x y)
相同。现在给 (+)
赋予两个参数确保((+) x y)
确实只是Num t => t
而不是Num t => t -> t
.
因此((*) .: (+)) 2 3 5
是 (*) ((+) 2 3) 5
这是 (*) 5 5
这是 25
,我相信这就是你想要的。
请注意f .: g
也可以写成(f .) . g
,和(.:)
也可以定义为(.:) = (.) . (.)
。您可以在这里阅读更多相关信息:
关于haskell - 当我在 Haskell 中用 + 组合 * 时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27664213/