2017-02-04 46 views
1

我有以下兩個「功能」:is_three和SOMESML:構造函數和函數如何區分?

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. 的情況說明如何能區分什麼構造函數和最新的功能
  2. 爲什麼沒有的函數case語句允許嗎?

回答

2

1)由於函數調用不是有效的模式,因此沒有任何區分。雖然這是事實,在類似

val x = FOO y 

,不可能沒有進一步上下文來判斷是否FOO y是一個功能或數據類型的構造函數(雖然命名約定建議後者),在模式匹配的情況下,沒有可能的含糊之處。如果FOO是數據類型構造函數,則FOO y是有效的模式,但如果FOO是函數,則不是。

2)至於爲什麼,假設你可能有函數出現在模式中。說你有以下兩種功能

fun square x = x*x 
fun cube x = x*x*x 

如果你可以像這樣定義一個函數:

fun f (square x) = x+1 
| f (cube x) = x+2 
| f _ = 3 

我應該f 64是什麼? 64是square 8所以應該是8 + 1 = 9?或者從cube 4 = 64開始應該是4 + 2 = 6?無論如何,編譯器應該如何識別這種模式的實例?通常,即使函數g是可計算的,如果給定值在g範圍內,也可能是不可判定的。此外,請注意,從數值64中恢復x = 4,模式匹配與「模式」cube x需要反轉功能cube。期望編譯器反轉任意函數太多了,特別是因爲它通常是不可能的。

從某種意義上說,你所談論的這種事情的弱形式是以n+k patterns的形式在Haskell中實現的。許多人認爲這是一個壞主意,最終被從語言中剔除。

+0

另一種選擇,我猜是把它留給運行時間而不是編譯時間。如果有兩個可以匹配的選項,則拋出一個運行時異常。 – Har

+0

p.s.第二種情況下你的意思是4 + 2 = 6嗎? – Har

+0

@哈是的。謝謝。 –

2

語言規範區分了函數和構造函數。因此,即使構造函數的類型看起來像函數,但對於如何使用構造函數和函數也有不同的規則。構造函數可能用於表達式,函數不能。

在語言設計層面的原因是構造函數和函數是不同的概念。構造函數是數據類型的「引入形式」,模式匹配是數據類型的「消除形式」。也就是說,構造函數是我們如何創建值,模式匹配是我們如何「用盡」值。例如,我們使用[]::來構造值列表。要使用值列表,我們在列表上進行模式匹配以提取頭部和尾部。相反,函數是輸入和輸出之間的關係,可能包含或不包含構造函數和模式匹配。

第二個問題是一個更難回答。首先,在您的示例| is_three(x)::xs => true andalso are_threes(xs)中並不完全清楚您的意思。推測你的意思是匹配x::xsnumbers併成功,如果is_three(x)。在這種解釋下,你寫的模式匹配是不完整的(當is_three錯誤時會發生什麼?)。該功能已經可以相當精確表達爲表達爲

fun are_threes(numbers) = 
case numbers of 
    [] => true 
    | x::xs => is_three(x) andalso are_threes(xs) 

有一個語言擴展在Haskell稱爲view patterns,它可以讓你在寫的模式功能。

+1

您也可以將數據類型定義視爲定義具有相同名稱的*值構造函數*和*模式構造函數/值解構器*。 *值構造函數*作爲值域中的函數,*模式構造函數/值解構器*在模式域中工作。僅僅因爲值構造函數具有函數類型,並不意味着函數通常具有與其匹配的隱式定義的模式構造函數。 –