7

maximumのような一般化された関数を作成しようとしましたPrelude。私の最初の素朴なアプローチは次のようになりました。
maximum' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum' mempty = Nothing
maximum' xs = Just $ F.foldl1 max xs

ただし、テストするとNothing、入力に関係なく常に返されます。
> maximum' [1,2,3]
> Nothing

モノイド型インスタンスの空の値を取得することは可能でしょうか。私が書いたテスト関数は正しく動作します:
getMempty :: (Monoid a) => a -> a
getMempty _ = mempty

> getMempty [1,2,3]
> []

私はすでにこれらの2つの質問を見ていましたが、答えが私の問題をどのように解決するかわかりませんでした:
Write a Maximum Monoid using Maybe in Haskell
Haskell Pattern Matching on the Empty Set

maximum'関数を機能させるにはどうすれば書き直せますか?

4

5 に答える 5

11

CA McCann がコメントで指摘しているように、値のパターン マッチはできず、パターンのみです。

maximum' mempty = Nothingは、実際には式 と等価maximum' x = Nothingです。引数は名前にバインドされてNothing返されます。

コードを機能させる方法は次のとおりです。

maximum' :: (F.Foldable a, Ord b, Eq (a b), Monoid (a b)) => a b -> Maybe b
maximum' xs
  | xs == mempty = Nothing
  | otherwise    = Just $ F.foldl1 max xs

つまり、値を と比較できます。値を取得できるようにするための制約と、同様に比較できるようにするための制約が必要であることに注意してください。xsmemptyMonoidmempty :: a bEq

もう 1 つのより洗練された解決策は、折り畳みを使用して、空のケースと空でないケースを区別することです。

maximum'' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum'' xs = F.foldl max' Nothing xs
  where max' Nothing x = Just x
        max' (Just y) x = Just $ max x y
于 2012-08-31T14:17:20.033 に答える
5

これを行うにはいくつかの方法があります (@opqdonut が示す方法は良い方法です)。の周りに「最大」モノイドを作成しMaybe、 を使用することもできますfoldMap

newtype Maximum a = Max { unMaximum :: Maybe a }

instance (Ord a) => Monoid (Maximum a) where
  mempty = Max Nothing
  mappend (Max Nothing) b = b
  mappend a (Max Nothing) = a
  mappend (Max (Just a)) (Max (Just b)) = Max . Just $ (max a b)

maximum' = unMaximum . F.foldMap (Max . Just)
于 2012-08-31T14:23:30.147 に答える
3

多くの方法があります.1つは(あなたが言及したように)のインスタンスを作成することですMonoidMaybeただし、値がない場合を区別するためにラップする必要があります。実装は次のようになります。

import Data.Monoid (Monoid, mempty, mappend)
import qualified Data.Foldable as F

-- Either we have a maximum value, or Nothing, if the
-- set of values is empty.
newtype Maximum a = Maximum { getMaximum :: Maybe a }
    deriving (Eq, Ord, Read, Show)

instance Ord a => Monoid (Maximum a) where
    mempty                      = Maximum Nothing

    -- If one part is Nothing, just take the other one.
    -- If both have a value, take their maximum.
    (Maximum Nothing) `mappend` y    = y
    x `mappend` (Maximum Nothing)    = x
    (Maximum (Just x)) `mappend` (Maximum (Just y))
                                     = Maximum (Just $ x `max` y)


maximum' :: (F.Foldable t, Ord a) => t a -> Maximum a
maximum' = F.foldMap (Maximum . Just)
于 2012-08-31T14:22:58.930 に答える
2

多くの人がすでに言っているように、値に対してパターン マッチを行うことはできません。

あまり知られていないことですが、パターン マッチングは Java のような言語のオブジェクト フィールドに相当する Haskell であることに間違いありません。密結合されたコードによる内部消費には価値がありますが、外部クライアント コードに公開したいものではない可能性があります。基本的に、コードの一部に型のコンストラクターを知らせると、型のセマンティクスが実際には変更されていなくても、他のコードを変更せずにこれらのコンストラクターを変更することはできなくなります。

ここでの最善の解決策は、実際に使用することFoldable.foldrです:

maximum' :: (F.Foldable a, Ord b) => a b -> Maybe b
maximum' = F.foldr step Nothing
    where step x Nothing = Just x
          step x (Just y) = Just (max x y)

foldrはインスタンスの一般化されたデストラクタまたはエリミネータであることに注意してくださいFoldable。その 2 つの引数は、「空でないFoldableものをどうするか」と「をどうするか」memptyです。これは、パターン マッチングよりも抽象的で再利用可能です。

于 2012-08-31T17:22:46.850 に答える
1

どうですか

maximum' :: (Monoid (t a), F.Foldable t, Ord a, Eq (t a)) => t a -> Maybe a
maximum' xs
   | xs == mempty = Nothing
   | otherwise    = Just $ F.foldl1 max xs

あなたは警備員を欠いていました。

関数ではgetEmpty、必要ありません。を使用するだけmemptyで、その型を推測できるようになります。

于 2012-08-31T14:17:23.697 に答える