tl;dr:
結論1:できない
あなたが最初に求めたものは、少なくとも私が思いつくことができるあなたが望んでいたもののどのバージョンでも不可能です。(以下を参照してください。)データ型を変更して中間計算を保存できるようにすれば、問題ないと思いますが、それでも関数unFold
はかなり非効率的であり、巧妙な最適化トリックの議題に反するようです!
結論 2: 型を変更して回避しても、目的が達成されるとは思わない
リストアルゴリズムの最適化は、元の最適化されていない関数を使用してステップ関数を計算したという問題の影響を受け、おそらく複雑な方法で発生します。
関数には平等がないため、ステップを効率的なものに最適化することはできません。unFold
コンパイラではなく、人間が行う必要があると思います。
とにかく、元の質問に戻ります。
折りたたむことができます。unFold = id ?
いいえ。
isSingleton :: [a] -> Bool
isSingleton [x] = True
isSingleton _ = False
もし私たちが持っていunFold :: ([x] -> y) -> Fold x y
たら、持っている必要foldSingleton
があるのと同じだったらunFold isSingleton
foldSingleton = Fold {start = False , step = ???}
where step はリストの要素を取り、結果を更新します。今isSingleton "a" == True
、私たちは必要です
step False = True
そして、なぜならisSingleton "ab" == False
、私たちは必要です
step True = False
これstep = not
までのところそうですが、isSingleton "abc" == False
必要なことも
step False = False
([x] -> y)
型の値で表現できない関数Fold x y
が存在するため、 は総関数であるため、のunFold :: ([x] -> y) -> Fold x y
ような関数は存在しません。fold . unFold = id
id
編集:
unFold
フォールドとしての表現を持つ関数でのみ作業することを期待していたので、これに納得していないことがわかりunFold.fold = id
ました。
展開できました。フォールド = id ?
いいえ。で取得できる機能だけに取り組み
たいと思っても、それは不可能だと思います。定義したと仮定して、質問に対処しましょうunFold
([x] -> y)
fold :: Fold x y -> ([x] -> y)
combine :: X -> Y -> Y
initial :: Y
folded :: [X] -> Y
folded = fold $ Fold initial combine
値の回復initial
は簡単です: initial = folded []
. の値を与える関数から の任意の値を組み合わせcombine
た関数に移行する方法がないため、元の復元はそうではありません。Y
Y
例として、X = Y = Int
私が定義した場合
combine x y | y < 0 = -10
| otherwise = y + 1
initial = 0
次に、正で使用するたびcombine
に1を追加するだけで、初期値は0であるため、出力に関しては区別できません。が負になることはないので、関数を回復する関数を定義することも不可能であることに注意してください。これは、が単射ではないという事実に要約されます。type の異なる値を typeの同じ値に運びます。y
y
folded
length
folded xs
unFold :: ([x] -> y) -> Fold x y
combine
fold
Fold x y
[x] -> y
したがって、私は 2 つのことを証明しました: if unFold :: ([x] -> y) -> Fold x y
then bothfold.unFold /= id
と now alsounFold.fold /= id
リフォールディングされたときに同じ値を持っているのを見て、 を取得したFold 0 (\_ y -> y+1)
か、Fold 0 combine
から戻ったかをあまり気にしないので、これにも納得していないに違いありません! unFold folded
もう一度ゴールポストを絞りましょう。unFold
を介して関数を取得できるときはいつでも作業したいかもしれませんfold
が、結果を再度折りたたんだときに同じ関数が得られる限り、一貫性のない答えが得られないことを嬉しく思います。次の質問でそれを要約できます。
折りたたむことができます。展開します。折る=折る?
つまり、 を介して取得できる一連の関数の ID にunFold
なるように定義できますか?fold.unFold
fold
step
サブリストの中間値に関する追加情報を保持せずに関数を計算するのは扱いやすい問題ではないため、これは不可能であると確信しています。
私たちが持っていたとしましょう
unFold f = Fold {start = f [], step = recoverstep f}
私たちは必要
recoverstep f x1 initial == f [x1]
したがって、x の Eq インスタンスがある場合 (警鐘を鳴らしてください!)、recoverstep は以下と同じ効果を持つ必要があります。
recoverstep f x1 y | y == initial = f [x1]
また、必要です
recoverstep f x2 (f [x1]) == f [x1,x2]
したがって、x の Eq インスタンスがある場合、recoverstep は次と同じ効果を持つ必要があります。
recoverstep f x2 y | y == (f [x1]) = f [x1,x2]
しかし、ここには大きな問題があります。変数x1
は、この式の右辺で自由です。これは、論理的には、ステップ関数が使用されている値を知っていない限り、x でステップ関数が持つべき値を判断できないことを意味します。などの値を Fold データ型に格納して機能させる必要f [x1]
があります。f [x1,x2]
これが、 を定義できない理由の決定的な要因unFold
です。データ型 Fold を変更して、中間リストに関する情報を保存できるようにすれば、それが機能することはわかりますが、現状ではコンテキストを回復することは不可能です。