8

だから私はタイプの2つの引数の関数のリストを持っています[a -> a -> a]

リストを取得して、左側で構成された長さ+1の引数を取得する関数のチェーンに構成する関数を作成したいと思います。たとえば、[f,g,h]すべてのタイプ[a -> a -> a]がある場合、次のような関数を作成する必要があります。

chain [f,g,h] = \a b c d -> f ( g ( h a b ) c ) d

また、それが役立つ場合、関数は引数で可換です(つまりf x y = f y x、すべてに対してx y)。

問題の関数の数がわかっていれば、リスト内包内でこれを行うことができます。これは、定義とほぼ同じです。それは、固定数の関数から動的な数へのストレッチであり、私は困惑しました。

これは私がこれまでに持っているものです:

f xs = f' xs
    where
        f' []   = id
        f' (x:xs) = \z -> x (f' xs) z

ロジックは正しいパスに沿っていると思います。タイプチェックはしません。

前もって感謝します!

4

2 に答える 2

8

nmからのコメントは正しいです。結果のタイプは入力リストの長さに依存するため、これは従来の方法では実行できません。それを機能させるには、もっと洗練された型システムが必要です。タイプでその長さをエンコードするリストを使用することでHaskellで妥協することができますが、それは苦痛で厄介です。

代わりに、引数はすべて同じタイプであるため、複数の引数の代わりに値のリストを受け取る関数を作成する方がはるかに便利です。したがって、必要なタイプは次のようになります。chain :: [a -> a -> a] -> [a] -> a

このような関数を作成するには、いくつかの方法があります。概念的には、引数リストの先頭と関数リストの末尾から開始し、最初の関数を最初の引数に適用して、タイプの何かを取得しますa -> a。そこから、その関数を次の引数に適用し、次に次の関数を結果に適用して、各リストから1つの要素を削除し、タイプが新しい関数を取得しますa -> a

リストの長さが正しく一致しない場合も処理する必要があります。前述のタイプエンコードされた長さとそれに関連する面倒以外に、それを回避する方法はありません。

于 2011-12-08T18:10:19.490 に答える
1

「関数のリストを持っている」という要件が実際の要件なのか、それとも回避策なのか、疑問に思います。同じ問題に直面しましたが、私の場合、関数のセットは小さく、コンパイル時に既知でした。もっと正確に言うと、私の仕事は4つのリストをxorで圧縮することでした。そして、私が欲しかったのは、3つのバイナリ関数を構成するためのコンパクトな表記法です。私が使用したのは小さなヘルパーです:

-- Binary Function Chain
bfc :: (c -> d) -> (a -> b -> c) -> a -> b -> d
bfc f g = \a b -> f (g a b)

例えば:

ghci> ((+) `bfc` (*)) 5 3 2 -- (5 * 3) + 2
17
ghci> ((+) `bfc` (*) `bfc` (-)) 5 3 2 1 -- ((5 - 3) * 2) + 1
5
ghci> zipWith3 ((+) `bfc` (+)) [1,2] [3,4] [5,6]
[9,12]
ghci> getZipList $ (xor `bfc` xor `bfc` xor) <$> ZipList [1,2] <*> ZipList [3,4] <*> ZipList [5,6] <*> ZipList [7,8]
[0,8]

それは元の質問にそのままでは答えられませんが、質問の件名が何であるかをほぼカバーしているので、希望はまだ役立つ可能性があります。

于 2014-02-16T02:00:35.647 に答える