10

私はHaskellの素晴らしい世界への第一歩を踏み出しました。演習として、リストの最大要素とそのインデックスを見つけるメソッドを実装したいと思います。この関数を「マキシ」と呼びましょう。リストでmaxiを呼び出すと、次の結果が返されます。

ghci> maxi [1, 3, 4, 1, 2, 3]
(4, 2)

4はこのリストで最大のintであり、インデックス2にあります。

私はこの関数を次のように実装しようとしました:

maxim :: (Ord a) => [a] -> (a, Int)
maxim l = 
  let pmaxim :: (Ord a) => [a] -> Int -> (a, Int) -- Internal function to do the work
      pmaxim [] _  = error "Empty list"           -- List is empty, error
      pmaxim [x] xi = (x, xi)                     -- List has one item, return it and the index
      pmaxim (x:xs) xi                            -- More than one item, break list apart
        | x > t     = (x, xi)                     -- If current item is bigger, return it and its index
        | otherwise = (t, ti)                     -- If list tail has a bigger item, return that
        where (t, ti) = pmaxim xs (ti + 1)        -- Get max of tail of the list
  in pmaxim l 0                                   -- Call internal function with start index

これを呼び出すと、本当に奇妙なことが起こります。最大要素の値を返した後、ghciがハングしているようです。

ghci> maxi [1, 3, 4, 1, 2, 3]
(4,

これはHaskellの遅延評価の性質と関係があると思いますが、ここで実際に何が起こっているのか、そしてそれを修正する方法を理解するのは難しいと感じています。また、Haskellでデバッグする方法について誰かが持っているかもしれないヒントにも本当に感謝しています。動作に影響を与えることなく、実行中に値を出力する簡単な方法はありますか?

組み込みのHaskell関数を使用してこの動作を実現するためのより良い方法がいくつかあることを認識していることを指摘したいと思います。Haskellを学ぶために、これを最初から実装しています。

ありがとうございました

4

2 に答える 2

23

これは、コードのわずかなバグが原因です。あなたが持っている:

where (t, ti) = pmaxim xs (ti + 1)

...しかし、実際には次のようになります。

where (t, ti) = pmaxim xs (xi + 1)

これによりコードが修正され、正しいソリューションが生成されます。

>>> maxim [1, 2, 3, 2, 1]
(3, 2)

ti誤ってコード自体を定義したため、の計算で無限ループが発生したため、コードがハングしました。これghcは十分にスマートなコンパイラでありt、の値に依存しないことを理解していることに注意してくださいti。そのため、インデックスを計算できない場合でも、バージョンは最大値を正常に計算できます。

純粋な計算をデバッグする標準的な方法はDebug.Traceモジュールです。

補足として、はるかに簡単な解決策があります。

import Data.List
import Data.Ord

maxi xs = maximumBy (comparing fst) (zip xs [0..])

編集:おっと、あなたがそれを最初から意図的に実装しているのを見ませんでしたが、それでもそのままにしておきます。

于 2013-01-27T18:20:00.917 に答える
0

私はあなたがすでにあなたの質問に答えられているのを見ます。ラムダ関数を使用して、再帰なしでそれを行うことができました。

maxim xs = foldr (\ (x,y) acc -> if (x == maximum xs) then (x,y) else acc) (0,head xs) (zip xs [0..])
于 2019-05-09T09:14:05.090 に答える