4

何度か、リストをトラバースして、リスト内の次の要素などにも依存するプロパティを持つ要素を選択したいと思っていました。f簡単な例として、指定された間隔で関数が符号を変更する回数をカウントするコードがあります[a,b]。これは、Cのような命令型言語ではかなり明白です。

for(double x=a; x<=b; x+=(b-a)/n){
    s*f(x)>0 ? : printf("%e %e\n",x, f(x)), s=sgn(f(x));
    }

Haskellでの私の最初の本能は、リストをテールで圧縮してから、フィルターを適用して要素を抽出することfstでした。しかし、それは不器用で非効率的であるように思われるので、私はそれを折り畳みにした。

signChanges f a b n = tail $       
    foldl (\(x:xs) y -> if (f x*f y)<0 then y:x:xs else x:xs) [a] [a,a+(b-a)/n..b]

いずれにせよ、これを行うための「正しい」方法があり(Haskellによくあるように)、それが何であるかわからない(または単に気付いていない)と感じます。これをより慣用的またはエレガントな方法で表現する方法についての助けは、一般的に、物事を行うための「正しい」方法を見つける方法についてのアドバイスと同様に、非常に高く評価されます。

4

3 に答える 3

4

リストフュージョンが機能するときに-O2を指定して実行すると、圧縮が効率的になります。この場合、折り目に頼る必要がないことは、モジュール性を向上させるため、Haskellの本質的な利点の1つです。

したがって、圧縮はそれを行う正しい方法です。

于 2012-10-07T10:00:36.663 に答える
3

これは、パラモルフィズムを使用した「バージョン」です(質問とはまったく同じではありませんが、パラモルフィズムを十分に説明する必要があります)para。標準ライブラリにはないため、最初に必要です。

-- paramorphism (generalizes fold)
para :: (a -> ([a], b) -> b) -> b -> [a] -> b
para phi b = step
  where step []     = b
        step (x:xs) = phi x (xs, step xs)

パラモルフィズムを使用することは、フォールドを使用することによく似ていますが、アキュムレータを見るだけでなく、残りの入力を見ることができます。

countSignChanges :: [Int] -> Int
countSignChanges = para phi 0
  where
    phi x ((y:_),st)  = if signum x /= signum y then st+1 else st
    phi x ([],   st)  = st


demo = countSignChanges [1,2,-3,4,-5,-6] 

尻尾をジッパーで締めるのと比較して良い点paraは、残りの入力を好きなだけ覗くことができることです。

于 2012-10-07T11:23:28.683 に答える
1

i番目の要素の値を計算する必要があるが、リストのj番目の要素に応じて、リストを可変または不変の配列に変換することをお勧めします。

したがって、現在の要素のインデックスに基づいて、foldまたは再帰呼び出しのいずれかで任意の計算を実行できます。

于 2012-10-07T09:57:25.807 に答える