我正在学习Haskell,但我遇到的情况是,我并不完全确定发生了什么。
我正在开展一个更大的项目,并一直在努力简化'我的代码。我已经了解了功能构成,我想我大多都了解它。然而,在突破极限的同时,我遇到了一种我不确定如何解释的情况。
经过几个小时的摆弄之后,我把它煮成了这个:
foo1 x y z = x == (y && z)
foo2 x y z = (x ==) . (&&) y z -- Error
foo3 x y = (x ==) . (&&) y
foo4 x = (x ==) . (&&) -- Error
为什么foo1
和foo3
有效,而foo2
和foo4
在我尝试定义时会出错?据我所知,没有理由在输入和输出中添加或删除等效参数应该改变函数。
修改:包含错误
foo2
会产生错误:
<interactive>:1:23: error:
• Couldn't match expected type ‘a -> a1’ with actual type ‘Bool’
• Possible cause: ‘(&&)’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘(&&) y z’
In the expression: (x ==) . (&&) y z
In an equation for ‘foo2’: foo2 x y z = (x ==) . (&&) y z
• Relevant bindings include
x :: a1 (bound at <interactive>:1:6)
foo2 :: a1 -> Bool -> Bool -> a -> Bool
(bound at <interactive>:1:1)
虽然foo4
给出错误:
<interactive>:2:15: error:
• No instance for (Eq (Bool -> Bool))
arising from an operator section
(maybe you haven't applied a function to enough arguments?)
• In the first argument of ‘(.)’, namely ‘(x ==)’
In the expression: (x ==) . (&&)
In an equation for ‘foo4’: foo4 x = (x ==) . (&&)
答案 0 :(得分:2)
让我们从功能应用开始。
a b
是将函数a应用于一个参数b。
a b c
是将函数a应用于两个参数b和c。
a b c d
是函数a对三个参数b,c和d的应用。
然后看看这两个函数的类型签名。
(&&) :: Bool -> Bool -> Bool
有两个参数
(.) :: (b -> c) -> (a -> b) -> a -> c
有三个参数,其中两个是函数
然后我们研究这四种情况。
foo1 x y z = x == (y && z)
(y&amp;&amp; z)是(&amp;&amp;)y z,完全应用。所以结果是Bool类型。
x ==布尔是(==)x布尔。所以x是Bool类型。
有效。
foo2 x y z = (x ==) . (&&) y z
(x ==)是一个需要一个参数的函数。
所以(x ==) . :: (a -> b) -> a -> c
然而,正如@Carcigenicate所说,你的(&amp;&amp;)已完全应用。
因此,编译器说,“无法将预期类型'a - &gt; a1'与实际类型'Bool'匹配”
foo3 x y = (x ==) . (&&) y
(.) :: (b -> c) -> (a -> b) -> a -> c
(。)函数组合需要函数(x ==)和(&amp;&amp;)y
现在需要的只是另一个产生c。
所以foo3只是foo1的无点风格。
它也有效。
foo4 x = (x ==) . (&&)
所以我们已经见面了(x ==)。
其类型签名是(a - &gt; b) - &gt; a - &gt; ç
然而,(&amp;&amp;):: Bool - &gt;布尔 - &gt;布尔
虽然它可以被视为Bool - &gt; (Bool - &gt; Bool),一个函数,它接受一个参数并产生一个Bool - &gt; Bool功能。
(Bool-> Bool)不是Eq的实例。它没有(==)。
因此编译器说“没有实例(Eq(Bool - &gt; Bool))”
据我所知,没有理由添加或删除等价物 输入和输出的参数应该改变函数。
当它们处于同一水平时,它仍然适用。
名称b c d =功能b c ddfullyly
name b c = function b c - 等待一个参数
name b = function b - 等待两个参数
name = function - 等待三个/所有参数
但是函数组合需要将两个单参数函数组合成一个参数函数(正确的一个输出类型需要匹配左一个输入类型。)
所以顺序首先是函数应用,然后是(。)/函数组合第二。并且您需要将(b-> c)和(a-> b)馈送到(。)以获得新的(a-&gt; c)函数。