操作符相对于函数的Haskell类型优先级



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

func x = map -1 x

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

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

如果我这样表示它,它很好,我得到了与原始相同的类型,但我不确定为什么它像这样分组。有人能解释一下吗?

例如,为什么不像这样:

func = x -> (map - 1) x

或类似的

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

如果你把这个函数写在一个文件中,例如:测试。它有func x = map -1 x并在解释器中使用:t func,它将回复:

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

我现在相信你是想问为什么

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) =>)。

但我不知道为什么它这样分组。有人能解释一下吗?例如,为什么不是这样呢?

   func = x -> (map - 1) x

优先级。语言定义指定(prefix)函数应用程序的优先级高于任何中缀操作符,因此

map -1 x

被解析为中音运算符(-)对两个操作数map1 x的应用,就像3 + 4 * 5被解析为3 + (4 * 5)一样,因为(*)的优先级比(+)高。

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

func x = map -1 x

就像我们要把

加括号一样
func x = map (-1) x

希望它从列表的每个元素中减去1,但不幸的是,-在数字字面值前面被认为是否定的,因此我们需要将其括起来以将其更改为减法函数:

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,而不是从1中减去列表的每个元素,您可以使用func x = map (subtract 1) x。正如hammar指出的那样,subtract函数的存在正是为了允许这样做。


你选择

func = x -> (map - 1) x

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

最新更新