2017-02-04 4 views
1

私は、次の2つの「機能」があります:彼らの両方が機能するように見える表面からSML:コンストラクタと関数はどのように区別されますか?

is_three; 
val it = fn : int -> bool 
SOME; 
val it = fn : 'a -> 'a option 

:is_threeとSOME

fun is_three(number) = 
    case numbers of 
     3 => true 
     | _ => false 

私はこれを取得するには、次の二つの文で書くときに戻り値。私は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

1)関数呼び出しは有効なパターンではないので、区別する必要はありません。

val x = FOO y 

のようなもので、それはFOO yは、パターンマッチングのコンテキストで、関数やデータ型コンストラクタ(命名規則は後者を示唆するだろうが)であれば教えてさらにコンテキストなしでは不可能であること、本当ですが起こりうる曖昧さはない。 FOOがデータ型コンストラクタである場合、FOOが関数でない場合、FOO yは有効なパターンです。

2)なぜ、パターンに関数が含まれている可能性があるとします。

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

f 64は何をする必要があります:あなたはこのような関数を定義することができればどのような次の2つの関数

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

を持っていたと言いますか? 64はsquare 8なので、8 + 1 = 9であるべきですか?または、cube 4 = 64から4 + 2 = 6である必要がありますか?いずれにしても、コンパイラはどのようにこのようなパターンのインスタンスを認識することになっていますか?一般に、関数gが計算可能であっても、与えられた値がgの範囲内にある場合、決定不能である可能性があります。さらに、 "パターン" cube xに対してパターンマッチングを使用して値64からx = 4を回復するには、関数cubeを反転する必要があることに注意してください。特に一般的には不可能なので、コンパイラが任意の関数を逆転させることは期待できません。

ある意味では、あなたが話しているような弱い形が、ハスケルでn+k patternsという形で実装されました。これらは多くの人にとって悪い考えであり、最終的にはその言語から落とされました。

+0

別のオプションは、コンパイル時ではなくランタイムに任せることです。一致する可能性のあるオプションが2つある場合は、ランタイム例外をスローします。 – Har

+0

p.s. 2番目のケースで4 + 2 = 6を意味しましたか? – Har

+0

@Harはい。ありがとう。 –

2

言語仕様では、関数とコンストラクタを区別しています。したがって、コンストラクタの型は関数のように見えるかもしれませんが、コンストラクタと関数をどのように使用するかについては異なる規則があります。コンストラクタは、式の場合に使用できますが、関数では使用できません。

言語設計レベルでこの理由は、コンストラクタと関数が異なる概念であるためです。コンストラクタはデータ型の「導入フォーム」であり、パターンマッチはデータ型の「削除フォーム」です。つまり、コンストラクタは値を作成する方法であり、パターンマッチングは値を使い切る方法です。たとえば、値リストの作成には[]::を使用します。値のリストを使用するには、頭と尾を抽出するためにリスト上でパターンマッチングを行います。対照的に、関数は、コンストラクタとパターンマッチを含む場合と含まない場合がある入力と出力の関係です。

2番目の質問は答えにくいです。まず、あなたの例で何を意味するのかが完全にはわかりません| 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) 

あなたがパターンで関数を記述することができますview patternsと呼ばれるHaskellの中言語拡張は、あるとして表現としての機能は、すでにかなり簡潔に表現することができます。

+1

また、データ型定義を、*値コンストラクタ*と*パターンコンストラクタ/値deconstructor *を同じ名前で定義することもできます。 *値コンストラクタ*は値の土地の関数として機能し、*パターンのコンストラクタ/値deconstructor *はパターンの土地で動作します。値コンストラクタに関数型があるという理由だけで、関数が一般的にそれにマッチする暗黙的に定義されたパターンコンストラクタを持っているわけではありません。 –

関連する問題