谁能解释这个Haskell难题?

时间:2015-08-29 14:01:18

标签: haskell

我知道使用了。运算符链一起运行,如下所示:

isLessThanZero x 
   | x < 0 = True
   | otherwise = False

(isLessThanZero . negate) 3 -- Produces True

或者使用$:

getNegNumbers x = map (*x) [-1, -2, -3]

filter isLessThanZero $ getNegNumbers 2 -- Produces [-2, -4, -6]

但是,如果我做的事情如下:

(subtract . negate) 1 2 -- 3
negate $ subtract 1 2 -- -1

这里的结果是不同的,它没有意义,因为这两个函数接受不同数量的参数。使用. negate函数检查数字是否为负数,但提供了两个参数。这可能意味着表达式是左关联的。

negate (subtract 1 2) -- -1
(subtract . negate) 1 2 -- 3

但这很令人困惑,因为在第一个例子中:

(isLessThanZero . negate) 3

表达式产生True,这意味着首先执行函数negate,然后调用isLessThanZero。但在最新的示例中,似乎先调用subtract,然后调用negate。所以我不确定这里发生了什么。但这更令人困惑:

subtract 1 2 -- Produces 1!

这意味着整个表达式:

(subtract . negate) 1 2 -- Produces 3!

是使用函数链的副作用。

我的理论就是这样,因此分解:

我们知道2 - (-1)= 3.所以,表达式仍然是正确联想的......我想。 negate仍然像前一个例子一样被调用,只是它影响第一个参数,而不是两个参数,这是有道理的,因为negate只接受一个参数,而我们根本没有映射函数。

所以,当谈到用不同数量的参数链接函数时,Haskell应该如何回应呢?

3 个答案:

答案 0 :(得分:4)

在Haskell上,函数是curry,所以:

group by

与:

相同
f :: a -> b -> c

因此,当您计算f :: a -> (b -> c) 时,您首先将f 1 2应用于a并获取类型为f的函数。然后,您应用b -> c并获取b

现在,让我们按照以下类型:

c

那么,Prelude> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c Prelude> :t negate negate :: Num a => a -> a Prelude> :t subtract subtract :: Num a => a -> a -> a Prelude> :t (subtract.negate) (subtract.negate) :: Num b => b -> b -> b 的类型是什么?

(subtract.negate) 2

正如您所看到的,Prelude> :t (subtract.negate) 1 (subtract.negate) 1 :: Num b => b -> b 获得了negate并获得了1,但-1获得了subtract,并提供了-1。然后,您将Int -> Int应用于2并获得Int -> Int

很快,3始终是右关联的,需要(.)(b -> c)。唯一棘手的部分是,(a -> b)本身可以是c

答案 1 :(得分:4)

Haskell方法是将所有函数视为接受一个参数并返回一个值,即使对于具有多个参数的函数也是如此。

因此,subtract函数的签名为:

subtract :: Num a => a -> a -> a

也可能会出现:

subtract :: Num a => a -> (a -> a)

一个函数,它接受一个数值参数并返回一个取一个数值并返回一个数值的函数。

考虑(.),其签名为:

(.) :: (y -> z) -> (x -> y) -> x -> z

它需要两个函数来返回一个函数。

如果您将其应用于(subtract . negate),则会有以下签名:

(subtract . negate) :: Num a => (a -> (a -> a)) -> (a -> a) -> (a -> (a -> a))

其中:

x = a
y = a
z = a -> a

签名此功能完全有效。

请注意,subtract 1 2的行为与2 - 1类似。

(subtract . negate)函数是一个函数,它接受一个数值,否定它并返回一个函数,该函数取另一个数值,从中减去否定值。

另请注意,negate (subtract 1 2)等于-1,而不是3

答案 2 :(得分:2)

  

这可能意味着表达式是左关联的。

我不明白你的意思是“少关联”。

函数应用程序是左关联的,意味着a b c解析为(a b) c

组合定义如下:(a . b) c = a (b c)

因此

(subtract . negate) 1 2
  =                        -- function application associates to the left
((subtract . negate) 1) 2
  =                        -- definition of composition
(subtract (negate 1)) 2
  =                        -- definition of subtract
2 - (negate 1)
  =                        -- definition of negate
2 - (-1)
  =                        -- definition of -
3

另一个表达式是这样的(带有a $ b = a b):

negate $ subtract 1 2
  =                       -- function application has higher precedence than any operator
negate $ (subtract 1 2)
  =                       -- definition of $
negate (subtract 1 2)
  =                       -- definition of negate
-(subtract 1 2)
  =                       -- definition of subtract
-1