さて、人々は通常、あなたが持っているデータ構造をリストではなく一種のツリーと呼びます。とにかく...
問題#1:Haskellはインデントに敏感であり、case
式がインデントされていません。これにより、解析エラーが発生します。
問題#2、そしてより大きな問題:あなたはタイプがどのように機能するかをまだ理解してMaybe
いません。より一般的な言語ではnullのように機能すると思われる印象を受けますが、これはあなたを失望させています。
たとえば、Javaのような言語でnull
は、他のほとんどの値が発生する可能性がある場所で発生する可能性のある値です。次のシグネチャを持つメソッドがある場合:
public Foo makeAFoo(Bar someBar)
...次に、次のいずれかの方法で呼び出すことが合法です。
// Way #1: pass in an actual value
Bar theBar = getMeABar();
Foo result = makeAFoo(theBar);
// Way #2: pass in a null
Foo result2 = makeAFoo(null)
theBar
ある意味でnull
「並列」であるか、より正確に言えば、同じタイプです。プログラム内で一方を他方に置き換えることができ、どちらの場合もコンパイルされます。
一方、Haskellでは、文字列"hello"
とNothing
は同じタイプではなく、一方を他方の場所で使用することはできません。Haskellは、次の3つのことを区別しています。
- そこにある必要がある文字列:
"hello" :: String
- オプションの文字列がない:
Nothing :: Maybe String
- オプションの文字列の存在:
Just "hello" :: Maybe String
#1と#3の違いは、関数に体系的に欠けているものです。を使用するMaybe a
と、値を使用する必要Just
があります。これは、「これは単なるではなくa
、Maybe a
。」を意味するラッパーのように機能します。
欠落している最初の場所Just
は、式の右側です。case
これは、次のように修正できます。
-- This still fails to compile!
cListGet :: CList a -> Maybe (a, CList a)
cListGet Nil = Nothing
cListGet xs@(NotNil nxs) =
case nxs of
-- I added 'Just' here and in the next line:
Sing x -> Just (x, Nil)
Append l r -> Just (fst $ cListGet (NotNil l), (Append (snd $ cListGet (NotNil l)), r))
しかし、これで終わりではありません。fst $ cListGet (NotNil l)
これは、逆の問題に悩まされているためです。は、をcListGet
返しますが、ではなくでMaybe (a, CList a)
機能fst
します。の結果をパターンマッチして、それがまたはであるかどうかをテストする必要があります。(これと同じ問題があなたのでも起こります。)(a, b)
Maybe (a, b)
cListGet
Nothing
Just (x, l')
snd $ cListGet (NotNil l)
第三に、Append
コンストラクターを間違って使用しています。との間に(Append foo, bar)
コンマを入れないでください。Haskellでは、この種のことは他のほとんどの言語よりも紛らわしいエラーメッセージを表示します。Haskellがこれを見ると、「構文エラーが発生した」とは表示されないためです。Haskellはほとんどの言語よりも文字通りであるため、最初の要素として、および2番目の要素としてペアを作成しようとしていると見なされるため、タイプがである必要があると結論付けられます。foo
bar
Append foo
bar
(Append foo, bar)
(NNList a -> NNList a, NNList a)
4番目の最後の問題:自分で設定した問題は明確に述べられていないため、良い答えはありません。の「頭」と「尻尾」を見つけたいと言いますCList a
。どういう意味ですか?Haskell[a]
タイプの場合、コンストラクターと、を使用する[]
と:
、これは明らかです。ヘッドはx
inx:xs
で、テールはxs
。です。
私が理解しているように、「頭」が意味するのは、再帰構造の左端の要素のようです。私たちはこのようにそれを得ることができました:
cListHead :: CList a -> Maybe a
cListHead Nil = Nothing
-- No need to cram everything together into one definition; deal with
-- the NNList case in an auxiliary function, it's easier...
cListGet (NotNil nxs) = Just (nnListHead nxs)
-- Note how much easier this function is to write, because since 'NNList'
-- doesn't have a 'Nil' case, there's no need to mess around with 'Maybe'
-- here. Basically, by splitting the problem into two functions, only
-- 'cListHead' needs to care about 'Maybe' and 'Just'.
nnListHead :: NNList a -> a
nnListHead (Sing a) = a
nnListHead (Append l _) = nnListHead l
ですから、「しっぽ」は他のすべてだと思うかもしれません。問題は、「他のすべて」があなたのまたはのサブパートではないということです。この例を見てください:CList
NNList
example :: CList Int
example = NotNil (Append (Append (Sing 1) (Sing 2)) (Sing 3))
「頭」は1
です。ただし、で定義されている構造のサブパートはexample
ありませ2
ん。それを得るには、元の形状とは異なる形状の新しい形状を作成する必要があります。それは可能ですが、率直に言って、初心者の練習としての価値はわかりません。3
1
CList
「サブパート」の意味が明確でない場合は、例をツリーと考えてください。
NotNil
|
v
Append
/ \
v v
Sing Append
| / \
v v v
1 Sing Sing
| |
v v
2 3
サブパート=サブツリー。