2017-03-27 8 views
1

私はhaskellを学んでいて、その言語を扱うためにさまざまな関数を書いています。私はこの関数を書いた:関数宣言のリストパターンの構文

doubleOneOrTail :: [t]->[t] 
doubleOneOrTail [x] = [x,x] 
doubleOneOrTail (x:xs) = xs 

これはまさに言うことです。 1要素のリストを2倍にするか、複数の要素のリストの末尾を返します。これなど、単一の要素またはリストのリストのリストのために働く一般的な構文は、私は次のようにこの関数を書き換えることができます。

doubleOneOrTail :: [[t]]->[[t]] 
doubleOneOrTail [[x]] = [[x,x]] 
doubleOneOrTail (x:xs) = xs 

私は次のように入力している場合、このエラーがスローされます。

doubleOneOrTail [1,2,3]

が、それはこれを受け入れない:

doubleOneOrTail [[[[1,2,3]、[2]]]]とのリストとして

トリートそれをシングル(その要素はリストのリストです)、それを倍にします。

パターン[a] - > [a]は単一の要素のリストと一致しませんが、何らかの方法でリストの順序に一致していることは明らかです。 Whlie [[a]] - > [[a]]はリストの複数のオーダーにマッチしています(単一のエレメントのリストではありません)。誰かがこれがどのように働いているのか説明できるなら、それは大いに感謝されるでしょう。

二次的な質問は、具体的にはリストの特定の順序を取る関数宣言を持つことが可能です(または望ましい場合もあります)。リストのリストだけを言う?

答えて

3

ここにあなたが驚いていることをよく理解しているように聞こえます。[a]は、リストのリストを含め、あらゆる種類のもののリストです。型推論が自動的に行うことを手作業で行うことができます。最初の定義を使用して、次のように書いてください:

let xs = [[[1,2], [3,4]], [[5]]] 
in doubleOneOrTail xs 

この時点で、GHCはタイプが一致していることを確認する必要があります。今

xs :: [[[Integer]]] -- really could be any Num type, but assume Integer 

我々は、引数として[[[Integer]]]doubleOneOrTailを呼んでいることから、GHCは二つのタイプが一致作ることaの代わりに、いくつかの具体的なタイプを見つけることを意味し、種類[a][[[Integer]]]を統一する必要があります。

[a] ~ [[[Integer]]] 
a ~ [[Integer]] 

したがって、私たちは物事のリストを倍増またはテーリングしています。それぞれのものは数字のリストです。型が本当に統一されているので、GHCは関数呼び出しをコンパイルし、結果として[[[5]]]を得ます。

あなたの2番目の質問に関しては、リストの特定の深さに制限することができるかどうかにかかわらず、通常はそうしてはいけません。この種の関数は、というパラメトリック多形と呼ばれ、どんな種類のaでも機能します。可能であれば、これは保存するのが良いという有用な特性です。正しく機能するために関数がa型の値を参照する必要がない場合は、関数の型を問わないはずです。

そのタイプを制限したいとします。他の偶発的な制限を加えずに深さ1のリストに制限する方法はわかりません。たとえば、あなたはそれが数字のリストでなければならないと言うことができる(と誰もがリストのNumインスタンスを定義していないことを願っています!):

doubleOneOrTail :: Num a => [a] -> [a] 

それともなど[Int]のような非常に特定のタイプ、それを制限することができます。これは、その型でのみ呼び出すことができることを保証します。

doubleOneOrTail :: [Int] -> [Int] 

しかし、上記のように、これらのアプローチのすべては、機能のタイプを不必要に制限しています。できるだけ一般的に定義する方が良いでしょう。また、そのタイプを制限したいと思っている他の問題を満たすための他の方法を見つけることをお勧めします。

+0

感謝を文字、数字、ブール値のリストを受け付けます。だから私が[[a]] - [[a]]をやっているとき、私は[[[]]]]に渡されたときにどのようなタイプaであるべきかを理解するために2つのレベルの指標を削除していました。 (これは、奇妙で直観的な結果につながる可能性があります) –

0

@amalloyに少しお答えします。おそらくあなたは、列挙型クラス制約で大丈夫:

doupbleOneOrTrail :: (Enum t) => [t] -> [t] 

は、だからあなたの関数は、たくさん助けなど

λ: doubleOneOrTail "foo" 
"oo" 
λ: doubleOneOrTail [False] 
[False,False]