我有以下两个“函数”:is_three和SOME
fun is_three(number) =
case numbers of
3 => true
| _ => false
当我写下以下两个陈述时,我得到了这个:
is_three;
val it = fn : int -> bool
SOME;
val it = fn : 'a -> 'a option
从表面看,它们似乎都是返回值的函数。但是,如果我尝试在case语句中使用is_three,我会得到以下结果:
stdIn:20.9-20.19 Error: non-constructor applied to argument in pattern: is_three
fun are_threes(numbers) =
case numbers of
[] => true
| is_three(x)::xs => true andalso are_threes(xs)
答案 0 :(得分:2)
1)由于函数调用不是有效模式,因此无需区分。虽然确实像
那样val x = FOO y
如果没有进一步的上下文来判断FOO y
是函数还是数据类型构造函数是不可能的(尽管命名约定会暗示后者),在模式匹配的上下文中,没有可能的歧义。如果FOO y
是数据类型构造函数,FOO
是有效模式,但如果FOO
是函数,则fun square x = x*x
fun cube x = x*x*x
不是。
2)至于为什么,假设你可以在模式中出现功能。假设您有以下两个功能
fun f (square x) = x+1
| f (cube x) = x+2
| f _ = 3
如果你可以定义这样的函数怎么办:
f 64
square 8
应该是什么? 64是cube 4 = 64
所以它应该是8 + 1 = 9吗?或者应该是{+ 1}}后4 + 2 = 6?无论如何 - 编译器如何识别这种模式的实例?通常,即使函数g
是可计算的,如果给定值在g
范围内,它也可能是不可判定的。此外,请注意从值64恢复x = 4
,并使用模式匹配"模式" cube x
需要反转函数cube
。期望编译器反转任意函数是太多了,特别是因为它通常是不可能的。
从某种意义上说,你所谈论的那种事物的弱形式是以n+k patterns的形式在Haskell中实现的。许多人认为这些是一个坏主意,并最终被语言删除。
答案 1 :(得分:2)
语言规范区分了函数和构造函数。因此,即使构造函数的类型看起来像函数,对于如何使用构造函数和函数也有不同的规则。可以在case表达式中使用构造函数,函数不能。
在语言设计层面上的原因是构造函数和函数是不同的概念。构造函数是"介绍形式"数据类型和模式匹配是"消除形式"数据类型。也就是说,构造函数是我们创造价值的方式,模式匹配是我们如何使用"值。例如,我们使用[]
和::
来构建值列表。要使用值列表,我们在列表上进行模式匹配以提取头部和尾部。相反,函数是输入和输出之间的关系,可能包含也可能不包含构造函数和模式匹配。
第二个问题更难回答。首先,您的示例| is_three(x)::xs => true andalso are_threes(xs)
中的含义并不完全清楚。据推测,您的意思是x::xs
与numbers
匹配,如果is_three(x)
则成功。根据这种解释,你写的模式匹配是不完整的(当is_three为false时会发生什么?)。该函数已经非常简洁地表达为表达式
fun are_threes(numbers) =
case numbers of
[] => true
| x::xs => is_three(x) andalso are_threes(xs)
Haskell中有一个名为view patterns的语言扩展,它允许您以模式编写函数。