Haskell在函数上键入运算符的优先级

时间:2013-05-28 17:09:15

标签: function haskell types operator-precedence typing

我必须派生出这个函数的类型:

func x = map -1 x

我已经找到了一种方法,使用提示将其更改为lambda表达式:

func = \x -> (map) - (1 x)

如果我这样表达,它的罚款和我的原型相同,但我不确定为什么它这样分组。有人可以解释一下吗?

例如,为什么不是这样的:

func = \x -> (map - 1) x

或类似的东西。

我知道这是一个无用的功能等但我无法改变功能,我只需要派生它的类型。

如果您在文件中编写此函数,例如: test.hs有func x = map -1 x 并在解释器中使用:t func,它将回复:

func :: (Num (t -> (a -> b) -> [a] -> [b]),
         Num ((a -> b) -> [a] -> [b])) =>
         t -> (a -> b) -> [a] -> [b]

3 个答案:

答案 0 :(得分:4)

我现在相信你想问为什么

func x = map -1 x

具有(Num (t -> (a -> b) -> [a] -> [b]), Num ((a -> b) -> [a] -> [b])) => t -> (a -> b) -> [a] -> [b]类型,以及如何组合表达式以使其具有该类型。

首先,您必须认识到空间是haskell中的运算符,并且具有最高优先级。

让我们使用#代替空格,我们可以使用最高优先级:

infixl 9 #
f # x = f x

我们可以在没有操作符的情况下用#:

替换和空格
func x = map - 1 # x

因为1和x之间的空格是唯一没有运算符的空格(-介于map1之间)。

由于#的优先级高于-,因此我们得到

func x = map - (1 # x)

或等效

func x = map - (1 x)

另一个例子

func2 x = map (-1) x
> :t func2
func2 :: Num (a -> b) => [a] -> [b]

这翻译为

func2' x = map # (-1) # x

但为什么-1之间没有#?在这种情况下,-等数字文字前面的1表示negate

> (-1)
-1
> (negate 1)
-1
> (subtract 1)
<interactive>:73:1:
    No instance for (Show (a0 -> a0))
      arising from a use of `print'
    Possible fix: add an instance declaration for (Show (a0 -> a0))
    In a stmt of an interactive GHCi command: print it

所以这个函数试图在列表上映射1的负数。为了实现这一点,需要将负1作为函数,这就是为什么它需要函数的数字实例(类型开头的Num (a->b) =>)。

答案 1 :(得分:2)

  

但我不确定为什么它这样分组。有人可以解释一下吗?例如,为什么它不是那样的:

   func = \x -> (map - 1) x

优先级。语言定义specifies that the precedence of (prefix) function application is higher than that of any infix operator,所以

map -1 x

被解析为中缀运算符(-)应用于两个操作数map1 x,因为3 + 4 * 5被解析3 + (4 * 5)因为更高(*)的优先级与(+)的优先级相比。

答案 2 :(得分:1)

虽然解释器已为表达式指定了一个类型,但它并不合理。让我们看看函数应该是什么

func x = map -1 x

看起来像我们想要像这样括起来

func x = map (-1) x

希望它从列表的每个元素中减去一个,但不幸的是,-被认为是在数字文字前面的否定,所以我们需要将它括起来将其改为减法功能:

func x = map ((-) 1) x

现在这个函数从1:

中减去列表中的每个数字
 func [1,2,3]
=[(-) 1 1,  (-) 1 2,   (-) 1 3]
=[  1-1,      1-2,        1-3]
=[   0,       -1,         -2]

类型是

func :: Num a => [a] -> [a]

如果要从列表的每个元素中减去一个,而不是从1中减去列表中的每个元素,则可以使用func x = map (subtract 1) x。正如hammar指出的那样,subtract函数的存在恰恰是为了允许这种情况。


您的替代

func = \x -> (map - 1) x

这不起作用,因为(-)的类型为Num a => a -> a -> a,而map的类型为(a -> b) -> [a] -> [b]。您不能从函数中减去一个函数,因为函数不是数值。