我必须导出这个函数的类型:
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之间的空格是唯一没有运算符的空格(-
在map
和1
之间)。
由于#
的优先级高于-
,我们得到
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
被解析为中音运算符(-)
对两个操作数map
和1 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,因为函数不是一个数值。