SML:构造函数和函数如何区分?

时间:2017-02-04 20:44:21

标签: pattern-matching sml

我有以下两个“函数”: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)
  1. case语句如何区分构造函数和函数是什么
  2. 为什么在case语句中不允许使用函数?

2 个答案:

答案 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::xsnumbers匹配,如果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的语言扩展,它允许您以模式编写函数。