私は最大部分列和問題を解決しようとしていて、ネイトの解決策を思いつきました
msss :: (Ord a, Num a) => [a] -> a
msss = f 0 0
f gmax _ [] = gmax
f gmax lmax (x:xs) =
let g = max (lmax + x)
in f (g gmax) (g 0) xs
ラッパー関数msss
を呼び出すと、次に が呼び出さf
れ、実際に処理が実行されます。解決策は良好で、正しく機能しています。なんらかの理由で、製品コードで最大部分列和問題を解かなければならない場合、それが私のやり方です。
しかし、そのラッパー関数は本当に私を悩ませます。Haskell では、プログラム全体を 1 行で書くことができるほど粘り強く、プログラムがほとんど 1 つの大きな式に過ぎないという点を真に強調する方法が気に入っています。そこで、余分な課題のためにラッパー関数を排除しようと考えました。
今、私は古典的な問題に遭遇しました: 匿名の再帰を行うには? 関数に名前を付けることができない場合、どのように再帰を行いますか? ありがたいことに、コンピューティングの父たちはずっと前に固定小数点コンビネーターを発見することでこの問題を解決しました。最も人気のあるものはY コンビネーターです。
Yコンビネーターをセットアップするためにさまざまな試みをしましたが、コンパイラーを通過できません。
msss' :: [Int] -> Int
msss' = (\y f x -> f (y y f) x)
(\y f x -> f (y y f) x)
(\g' gmax lmax list -> if list == []
then gmax
else g' (max gmax lmax + head list)
(max 0 lmax + head list)
tail list)
ただ与える
Prelude> :l C:\maxsubseq.hs [1 of 1] Compiling Main ( C:\maxsubseq.hs, interpreted ) C:\maxsubseq.hs:10:29: Occurs check: cannot construct the infinite type: t0 = t0 -> (([Int] -> Int) -> [Int] -> Int) -> [Int] -> Int In the first argument of `y', namely `y' In the first argument of `f', namely `(y y f)' In the expression: f (y y f) x C:\maxsubseq.hs:11:29: Occurs check: cannot construct the infinite type: t0 = t0 -> (([Int] -> Int) -> [Int] -> Int) -> [Int] -> Int In the first argument of `y', namely `y' In the first argument of `f', namely `(y y f)' In the expression: f (y y f) x C:\maxsubseq.hs:12:14: The lambda expression `\ g' gmax lmax list -> ...' has four arguments, but its type `([Int] -> Int) -> [Int] -> Int' has only two In the second argument of `\ y f x -> f (y y f) x', namely `(\ g' gmax lmax list -> if list == [] then gmax else g' (max gmax lmax + head list) (max 0 lmax + head list) tail list)' In the expression: (\ y f x -> f (y y f) x) (\ y f x -> f (y y f) x) (\ g' gmax lmax list -> if list == [] then gmax else g' (max gmax lmax + head list) (max 0 lmax + head list) tail list) In an equation for `msss'': msss' = (\ y f x -> f (y y f) x) (\ y f x -> f (y y f) x) (\ g' gmax lmax list -> if list == [] then gmax else g' (max gmax lmax + head list) (max 0 lmax + head list) tail list) Failed, modules loaded: none.
から に変更 f (y y f)
するf (y f)
だけで
C:\maxsubseq.hs:11:29: Couldn't match expected type `[Int] -> Int' with actual type `[Int]' Expected type: (([Int] -> Int) -> t1 -> t0) -> t2 -> t0 Actual type: ([Int] -> Int) -> t1 -> t0 In the first argument of `y', namely `f' In the first argument of `f', namely `(y f)' Failed, modules loaded: none.
コンビネータを外部で定義するだけで別のアプローチを試みましたが、これはまだ機能せず、1 つの式でそれを行うという私の課題を実際には満たしていません。
y f = f (y f)
msss' :: [Int] -> Int
msss' = y (\g' gmax lmax list -> if list == []
then gmax
else g' (max gmax lmax + head list)
(max 0 lmax + head list)
tail list)
私がしていることのどこが悪いのか分かりますか? 私は途方に暮れています。Haskell はそういうものばかりだと思っていたからです。無限のデータ構造を持っているのに、なぜ無限型に問題があるのでしょうか? 型付けされていないラムダ計算が矛盾していることを示したパラドックスと関係があると思います。よくわかりませんが。誰かが明確にできれば良いでしょう。
また、再帰は常にfold関数で表現できるという印象を受けました。折り目を使用するだけでそれを行う方法を誰かに教えてもらえますか? ただし、コードが単一の式であるという要件は依然として有効です。