3

Haskellを始めたばかりです。Haskellの標準関数を模倣した関数を作成しようとしていますreplicateが、再帰を使用しています。例えば、

Prelude> replicate 3 "Ha!"
["Ha!","Ha!","Ha!"]

タイプである必要がありInt -> a -> [a]ます。これまでのところ、私は持っています:

myReplicate :: Int -> a -> [a]
myReplicate x y = y : myReplicate (x-1) y
myReplicate 0 y = [ ]

ただし、私の関数は常に無限リストを生成します。

Prelude> myReplicate 3 "Ha!"
["Ha!","Ha!","Ha!","Ha!","Ha!","Ha!","Ha!",...
4

3 に答える 3

9

最初のケースより前に 2 番目のケースを配置する必要があります。

myReplicate :: Int -> a -> [a]
myReplicate 0 y = [ ]
myReplicate x y = y : myReplicate (x-1) y
于 2015-06-20T21:16:03.983 に答える
5

あなたのコードは (少なくとも GHC では) 警告を生成するはずです:

Pattern match(es) are overlapped
In an equation for 'myReplicate': myReplicate 0 y = ...

何が起こっているかというと、コードは、記述した順序 (トップダウン) で、記述した各定義に対して入力を照合しようとします。を記述するf x = ...と、x変数は、それが表す型の任意の値と常に一致します。定義内のすべてのバインディングが一致する場合、その定義が使用されます。

あなたの場合、最初の定義はmyReplicate x y = y : myReplicate (x-1) y. 私が言ったように、バインディングを含め、渡した値xy一致します。@Alec によって提案された解決策は、最も具体的なパターンを最初に記述し、キャッチオール パターンを最後に記述することで、この問題を回避する方法を示しています。0x

別の解決策はガードを使用することです:

myReplicate :: Int -> a -> [a]
myReplicate x y
    | x > 0  = y : myReplicate (x-1) y
    | x == 0 = []
    | otherwise = [] -- or throw an exception, or use Maybe

このように、条件を適切に記述すれば (つまり、条件が相互に排他的であれば)、使用する式を任意の順序で記述できます。if ... else if ... else if ... else ...条件は、命令型言語のチェーンのように、最初に上から評価され、次に条件が真になるまで下に評価されることに注意してください。

于 2015-06-20T21:24:42.717 に答える
1

マップを使用できます:

myReplicate :: Int -> a -> [a]
myReplicate n x = map (const x) [1..n]

$>Data.Functor からも使用できます。

import Data.Functor 
myReplicate :: Int -> a -> [a]
myReplicate n x = [1..n] $> x
于 2020-02-08T21:23:03.630 に答える