型の問題については、これが私を大いに助けてくれたトリックです。このようなメッセージに完全に困惑するたびに、私は次のことを行います。
- 問題の関数に型シグネチャがある場合は、それを削除して、何かが変わるかどうかを確認します。コンパイルできたら、ghci にタイプを尋ねます ( を使用
:t
)。コンパイルされない場合、少なくともエラー メッセージが異なるため、別の手がかりが得られる可能性があります。
- 型シグネチャがない場合は、1 つ追加します。コンパイルされない場合でも、エラー メッセージから別の手がかりが得られる場合があります。
- それでも問題が解決しない場合は、関数内の各式に型宣言を一時的に追加します。
ScopedTypeVariables
(多くの場合、実際に何が起こっているかを確認するために、いくつかの式を分割する必要があります。プラグマを一時的に有効にする必要がある場合もあります。) 再度コンパイルして、エラー メッセージを確認します。
最後の 1 つはより多くの作業ですが、私はその演習から多くのことを学びました。それは通常、私が考えている型と GHC が考えている型との間に不一致がある正確な場所を特定します。
それでは、コードに型シグネチャを追加することから始めましょう。
myrepli :: [a] -> Int -> [a]
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error
ああ、今度はコンパイラ エラーが発生します。
amy.hs:9:27:
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
In the first argument of `myrepli', namely `x'
In the first argument of `(++)', namely `(myrepli x n)'
In the expression: (myrepli x n) ++ (repli xs n)
問題は への呼び出しにありmyrepli x n
ます。関数myrepli
はリスト/文字列を想定していますが、1 つの文字を渡しています。その最後の行を次のように変更します。
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
その時点で、コード内に他のエラーが見つかります。ただし、コードを修正するのではなく、別の方法を紹介しましょう。
repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []
-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)