2017-03-06 6 views
3

私はHaskellを初めて使い、構文に慣れるための簡単な関数を書こうとしています。特定の要素を特定のインデックスのリストに追加する独自の関数を記述したいと思います。ここで私はアトムに(私のテキストエディタを)書いたものです:ハスケルでガードを正しく使うには?

addElem :: a->[a]->Int->[a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) where a = take index list; b = drop index list 
| otherwise    = list 

アイデアは、それがlistの要素と同じ型のものである限り、インデックスがIntelemあるようフリークアウトではないということですしかし、これをghciにロードしようとすると、「|で解析エラーが発生します」。私は引数の種類を制約する必要がありますか?私はHaskellを学んでいますが、インデントがどのように機能するかを完全に説明する部分にはいないので、私のエラーもそこにあるかもしれません。

+3

'where'ブロックが式につけられていない、つまり' x where decls'は式ではありません( 'let decls in x'とは対照的に、式です)。 'where'ブロックは宣言に付ける必要があります。この場合は、' addElem'宣言に追加する必要があります。そのため、最後のガードステートメントも同様に宣言本体の*後*に配置する必要があります。解析エラーは間違った型を使うことと決して関係しないことに注意してください。つまり、コンパイラがコードを理解していないことを意味します。これはインデントエラーでもありません。 – user2407038

+2

@ user2407038答えが必要 – jberryman

+0

'index'が大きすぎると' elem'を無視するのは本当ですか?これは、 'index'が<0である時に要素を前置することと比べて少し非対称です。私は' otherwise = list ++ [elem] 'が理にかなっていると思います。 – chepner

答えて

11

whereブロックは、関数全体の最後に発生する必要があり、すべてのケースで共有されます。

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = let a = take index list; b = drop index list in a ++ (elem:b) 
| otherwise    = list 

はまた、letlet (a,b) = splitAt index list in ...ように、より簡潔に書くことができることに注意してください:あなたは、おそらくlet使用することを意味しました。 splitAtもPreludeにあります。もちろん、whereブロックを関数の最後に移動することもできます(Haskellの怠惰はこれを簡単に理由づけます)。個人的に

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) 
| otherwise    = list 
where 
    a = take index list 
    b = drop index list 

それはabは機能の他の場所で使用できることを示唆しているので、私はこのあまり好きです。

2010 Haskell Reportのセクション4.4.3は、whereが許可されている場所についてさらに詳しく説明しています。

関連する問題