为什么函数组合在应用于采用多个参数的函数时有效?
Why does function composition work when applied to functions that take multiple arguments?
我想我在写出这些步骤时理解函数应用程序是如何工作的,但是类型签名算法并没有在我的脑海中加起来。为冗长的前奏道歉(没有双关语)。
举一个具体的例子,这个例子是 Stefan Höck's Idris2 tutorial:
的一个稍微改动的例子
plusTwo : Integer -> Integer
plusTwo = (+2)
twice : (Integer -> Integer) -> Integer -> Integer
twice f n = f (f n)
在 REPL 中:
> twice plusTwo 3
7
> (twice . twice) plusTwo 3
11
我所知道的
Haskell 和 Idris 中的函数都是 curried and every function takes only one argument
函数组成为implemented为
f . g = \x -> f (g x)
函数应用是左关联
类型签名中的箭头是 正确的 关联的
写出(twice . twice) plusTwo 3
表达式可以显式括号为
((twice . twice) plusTwo) 3
可以重写为
------f-------- -n-
(twice (twice plusTwo)) 3
|
V
------f-------- (------f-------- -n-)
(twice plusTwo) ((twice plusTwo) 3 )
\------------------/
|||
plusTwo (plusTwo 3)
|||
7
\-----------------------------------/
|||
twice plusTwo 7
似乎类型签名不匹配
下面的函数组合运算符的类型签名表明它采用单参数函数,
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
但是 twice
需要两个参数(即 (t -> t) -> t -> t
),所以这让我失望。
我想当返回的 lambda 的参数 x
本身是一个函数时,这是唯一可行的方法。能这么简单吗?
twice . twice
((a -> a) -> a -> a) -> ((a -> a) -> a -> a) -> ?
(---b---- -> --c---) -> (---a---- -> --b---) -> (a -> c)
? = (a -> a) -> a -> a
或者,换句话说,twice . twice
接受一个签名为 (a -> a) -> a
的函数(这里的 a
是 Integer
)。
如果上面的内容是正确的,那么我可以找出参与函数具有不同输入参数的函数组合(例如,twice . (+2)
)。
是的,仅此而已。如果把twice
的签名写成
可能会更容易思考
twice :: (Integer -> Integer) -> (Integer -> Integer)
如您所知,这等同于柯里化。这样看来,twice
是一个参数的函数,再次将它与 twice
组合起来似乎非常合理。
我想我在写出这些步骤时理解函数应用程序是如何工作的,但是类型签名算法并没有在我的脑海中加起来。为冗长的前奏道歉(没有双关语)。
举一个具体的例子,这个例子是 Stefan Höck's Idris2 tutorial:
的一个稍微改动的例子plusTwo : Integer -> Integer
plusTwo = (+2)
twice : (Integer -> Integer) -> Integer -> Integer
twice f n = f (f n)
在 REPL 中:
> twice plusTwo 3
7
> (twice . twice) plusTwo 3
11
我所知道的
Haskell 和 Idris 中的函数都是 curried and every function takes only one argument
函数组成为implemented为
f . g = \x -> f (g x)
函数应用是左关联
类型签名中的箭头是 正确的 关联的
写出(twice . twice) plusTwo 3
表达式可以显式括号为
((twice . twice) plusTwo) 3
可以重写为
------f-------- -n-
(twice (twice plusTwo)) 3
|
V
------f-------- (------f-------- -n-)
(twice plusTwo) ((twice plusTwo) 3 )
\------------------/
|||
plusTwo (plusTwo 3)
|||
7
\-----------------------------------/
|||
twice plusTwo 7
似乎类型签名不匹配
下面的函数组合运算符的类型签名表明它采用单参数函数,
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
但是 twice
需要两个参数(即 (t -> t) -> t -> t
),所以这让我失望。
我想当返回的 lambda 的参数 x
本身是一个函数时,这是唯一可行的方法。能这么简单吗?
twice . twice
((a -> a) -> a -> a) -> ((a -> a) -> a -> a) -> ?
(---b---- -> --c---) -> (---a---- -> --b---) -> (a -> c)
? = (a -> a) -> a -> a
或者,换句话说,twice . twice
接受一个签名为 (a -> a) -> a
的函数(这里的 a
是 Integer
)。
如果上面的内容是正确的,那么我可以找出参与函数具有不同输入参数的函数组合(例如,twice . (+2)
)。
是的,仅此而已。如果把twice
的签名写成
twice :: (Integer -> Integer) -> (Integer -> Integer)
如您所知,这等同于柯里化。这样看来,twice
是一个参数的函数,再次将它与 twice
组合起来似乎非常合理。