2012-03-01 6 views
6

私はいつもこの形式で私のリストを生産する再帰関数を書きました:Haskellのリスト連結対(頭:尾)形式

recursiveFunc :: [a] -> [b] 
recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs where 
    change :: a -> b 
    change x = ... 

私は、上記のような任意の関数がa -> b場合のために書くことができます実現し、単純にmap[a]に設定しましたが、このような状況を例にとってください。

HLintは[change x] ++ recursiveFunc xschange x : recursiveFunc xsに置き換えることを示唆しています。

この提案は純粋に審美的ですか、またはHaskellがどのように機能を実行するかに影響しますか?

+4

まあ、最初の1つの引数では、 '++' *は 'cons'を一度実行してから終了しますが、単一の値の前に丸める方法です。 – delnan

+2

あなたのバージョンには、複数の要素がリストの先頭に追加されるように、ある時点で関数を変更しようとすると、変更することが少なくなるという利点があります。 –

+0

hlintの提案は、式の結果を変更しません。 –

答えて

9

[change x] ++ recursiveFunc xsを使用する場合は、余分な1要素リストを作成してから、++関数で区切ります。使用しない:を使用してください。

プラス++は、:コンストラクタを使用する関数です。 :を直接使用すると、関数を呼び出す必要はありません。

したがって、:を使用する方が理論的には効率的です(しかし、コンパイラはこれらの違いを最適化するかもしれません)。

4

主な利点は、change x : blahが明確であることです。(:)は、正確に何をしようとしているか(1つの要素をリストに追加する)です。なぜ2つの機能を呼び出すのですか?

提案された方法は、やや効率的です。あなたの方法では、1要素のリストが作成された後、それをスローして別のリストリンクに置き換えます。もう1つの方法は、1つのリストリンクを作成するだけです。それは、その差は時間の99%を占めるには十分小さいと言います。それはnormalformていないので

4

recursiveFunc (x:xs) = [change x] ++ resursiveFunc xs 

は少し紛らわしいです。

(++) (a:as) bs = a:((++) as bs) 
(++) [] bs = bs 

-- => 

recursiveFunc (x:xs) = (change x):((++) [] resursiveFunc xs) 

-- => 

recursiveFunc (x:xs) = (change x):(resursiveFunc xs) 

Haskellのコンパイラは自動的にこのような変換を適用します。それは++は、その定義の1つの右辺と直接交換することができることを意味しています。

しかし、それはとても簡単なので、コードを読みにくくしています。誰かがそれを見て「待って...何を?」と尋ねる。

関連する問題