2016-11-12 4 views
0

私は、リスト内で最大の奇数整数を取得する関数haskellを作成しようとしています。簡単に聞こえるし、私はそれを行うことができると確信していたが、私は立ち往生しているように見える!ここに私のコードは、これまでのところ、それは奇数と偶数の両方を含むリスト内の最大数を返し、次のとおりです。詳細を求めるHaskell関数

maximum :: (Ord a) => [a] -> a 
maximum [x] = x 
maximum (x:xs) = max x (maximum xs) 

はあなたの助けのために事前にありがとうございます!

+7

'maximumOdd = maximum。フィルタ奇数 ' – Alec

+0

型制約を 'Ord a => a'から' Integral a => a'に変更する必要があることに注意してください。 – mnoronha

+0

@mnoronhaええ、 'odd'の存在は' Integral'型を意味します –

答えて

2

まず、リスト内の要素だけが問題になる場合は、関数が合計ではないため(つまりエラーが発生するため)、その結果を考慮して結果の種類を変更することをお勧めしますその可能性:

また、既に言及したように - oddは、Ordではなく、Integralであることが必要です。故障を考慮してその結果に我々パターンマッチ -

maximodd :: Integral a => [a] -> Maybe a 
maximodd xs = case filter odd xs' of 
       [] -> Nothing 
       xs' -> Just (maximum xs') 

機能filter oddは、すべての非奇数の要素(すなわち、すべての偶数)を除去します。

あなたの本来の機能で作業したい場合は、コードが多くのトリッキー取得します。

maximum :: Integral a => [a] -> a 
maximum [x] = x 
maximum (x:xs) = let y = maximum xs 
       in if x >= y && odd x 
         then x 
         else if x < y && odd y 
          then y 
          else ?? 

うーん - 私はあなたがそれはこのように動作させることができるとは思わない - 多分ヘルパー機能付き。また、より複雑である

maximum :: Integral a => [a] -> Maybe a 
maximum xs = maximum' Nothing xs 
    where maximum' Nothing (x:xs) = if odd x 
            then maximum' (Just x) xs 
            else maximum' Nothing xs 
     maximum' (Just y) (x:xs) = if odd x 
            then maximum' (Just $ max x y) xs 
            else maximum' (Just y) xs 
     maximum' x _ = x 

- とHaskellのは間違いなく、複雑さのために知られていない;)

+0

完全性!このために 'safe'パッケージにも便利な機能があります! –

2
maximumOdd :: Integral a => [a] -> Maybe a 
maximumOdd = foldl' go Nothing 
    where 
    go Nothing x | odd x = Just x 
    go (Just gr) x | odd x && x > gr = Just x 
    go acc _ = acc 
1

は、すべてはあなたの言語について何かを教えるいくつかのオプションがあります。 まず第一に、イプシロンハルが記載されているという問題があります。今のところ、私はコードにエラーを投げるだけです。

maximumOddError :: a 
maximumOddError = error "maximumOdd: list contains no odd element" 

最も重要な問題は、開始時に奇数があるかどうかわからないことです。だから、あなたはそのテストを延期しなければなりません(私たちはそれに来るでしょう)か、フィルターをかけて一度にチェックインする必要があります。

オプション1:末尾再帰

最も簡単な解決策は一つに両方のチェックを行うことです。一般的に、これは最適な最適化手法です。今のところ、エラー処理と反復が分かれています。

maximumOdd :: (Integral a) => [a] -> a 
maximumOdd ls = case dropWhile even ls of 
        [] -> maximumOddError 
        n:ns -> findOddMax n ns -- n is definitely odd 
    where 
    findOddMax currentMax [] = currentMax 
    findOddMax currentMax (x:xs) 
     | even x   = findOddMax currentMax xs 
     | x < currentMax = findOddMax currentMax xs 
     | otherwise  = findOddMax x   xs 

はオプション2:ソート

代わりのすべての部分を見て、あなたはまた、高レベルの視点を取ることができます。検索する理由は、リストをソートして検索する要素を一方の端に表示させることができるときです。もちろんフィルタリングしなければならないので、基本的にはlast . sort . filter oddのようなものです。それは降順でリストをソートする方が良いですので、しかしlastは、別のトラバースです:headは空のリストに失敗すること

import Data.List (sortBy) 

maximumOdd :: (Integral a) => [a] -> a 
maximumOdd = head . sortBy reverseOrder . filter odd 
    where 
    reverseOrder a b = compare b a 

注意。したがって、エラー処理はあまり良くありません。しかし、それは簡単に追加する必要があります。どのような性能は単純なものと比べて何ですか?maximum . filter odd?教えてください!

オプション3:

を扱う素敵なエラーで末尾再帰は、今のMaybeを経由して、いくつかの優れたエラー処理を追加してみましょう。それを行う最も簡単なバージョンは、テールの再帰的なバージョンです。エラー処理と反復を分離しています。

maximumOdd :: (Integral a) => [a] -> Maybe a 
maximumOdd ls = case dropWhile even ls of 
        [] -> Nothing 
        n:ns -> Just $ findOddMax n ns -- n is definitely odd 
    where 
    findOddMax … -- same as above 

これは非常にdfeuer年代と同じ方法です。彼は、既存の関数をより短く効率的にするために、より多くの既存の関数を使用しました。そして、エラー処理を再帰に統合しました。これが、Haskellのプログラマーが最も経験したことです。 (あなたは、ラッピングとアンラッピングのパフォーマンスコストについて議論が、えっ可能性があり、あなたがそれを必要とするときがあることを行う。。)

オプション4:

を扱う素敵なエラーでソートをこの1つは、同様に簡単です、素敵がありますので、バージョンheadが必要です。

import Data.Maybe (listToMaybe) 

maximumOdd :: (Integral a) => [a] -> Maybe a 
maximumOdd = listToMaybe . sortBy reverseOrder . filter odd 
    where 
    reverseOrder a b = compare b a 

オプション5:最後に

を扱う素敵な誤りとの直接トラバーサル、我々は戻って最初のアプローチにしています。しかしMaybeではエラーチェックを延期できます。事は:あなたはいくつかの特別なツールを知る必要がある、またはそれらを発明しなければならない。私はちょうど既存のものを使用します。

import Control.Applicative ((<|>)) 

maximumOdd :: (Integral a) => [a] -> Maybe a 
maximumOdd []     = Nothing 
maximumOdd [x] | even x = Nothing 
        | otherwise = Just x 
maximumOdd (x:xs) | even x =   maximumOdd xs 
        | otherwise = max x <$> maximumOdd xs -- either "max x" applied inside the Maybe-construct 
           <|> Just x    -- or x, if that produced an error 
+0

ありがとうございました!私はこれを読んだ後、何が起こったのかをよりよく理解していると思います。ありがとうございました! –

関連する問題