4

値が欠落しているデータを扱っています。これは、Maybe 値のリストとして単純に表されます。欠損値を単純に無視するさまざまな集計/統計操作を実行したいと思います。

これは、次の質問に関連しています。

Haskell で Maybe Int のリストを合計する慣用的な方法

多分モノイドを使用して値をカスタム操作と簡単に組み合わせる方法は?

ただし、前者の質問はNothing、値が欠落している場合に返すことに満足しており、これは私の場合のオプションではありません。Numのインスタンスを作成するソリューションがありますMaybe。ただし、これは足し算と掛け算に固有のものであり、他にもいくつかの問題があることを意味します。

instance Num a => Num (Maybe a) where
  negate      = fmap negate
  (+)         = liftA2 (+)
  (*)         = liftA2 (*)
  fromInteger = pure . fromInteger
  abs         = fmap abs
  signum      = fmap signum

それに基づいて、次のようなことができます。

maybeCombineW :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
maybeCombineW f (Just x)  (Just y)  = Just (f x y)
maybeCombineW _ (Just x)  Nothing   = Just x
maybeCombineW _ Nothing   (Just y)  = Just y
maybeCombineW _ Nothing   Nothing   = Nothing


maybeCombineS :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
maybeCombineS f (Just x)  (Just y)  = Just (f x y)
maybeCombineS _ _          _        = Nothing


class (Num a) => Num' a where
  (+?) :: a -> a -> a
  (*?) :: a -> a -> a
  (+!) :: a -> a -> a
  (*!) :: a -> a -> a
  (+?) = (+)
  (*?) = (*)
  (+!) = (+)
  (*!) = (*)

instance {-# OVERLAPPABLE  #-} (Num a) => Num' a
instance {-# OVERLAPPING  #-} (Num' a) => Num' (Maybe a) where
  (+?) = maybeCombineW (+?)
  (*?) = maybeCombineW (*?)
  (+!) = maybeCombineS (+!)
  (*!) = maybeCombineS (*!)


sum' :: (Num' b, Foldable t) => t b -> b
sum' = foldr (+?) 0

sum'' :: (Num' b, Foldable t) => t b -> b
sum'' = foldr (+!) 0

これについて私が気に入っているのは、 lenientsum'と strictの 2 つの関数sum''があり、必要に応じて選択できることです。同じ関数を使用して任意のNumインスタンスを合計できるため、リストMaybeを変換せずに同じコードをリストに再利用できます。

これについて私が気に入らない点: インスタンスが重複しています。また、加算と乗算以外の演算については、新しい型クラスを指定して新しいインスタンスを作成する必要があります。

したがって、おそらく2番目の質問で提案された行に沿って、適切で一般的な解決策を得ることが何とか可能かどうか疑問に思っていましたNothing.これはmempty、問題の操作の .

これを行う良い慣用的な方法はありますか?

編集:これまでのところ最良の解決策は次のとおりです。

inout i o = ((fmap o) . getOption) . foldMap (Option . (fmap i))
sum' = Sum `inout` getSum
min' = Min `inout` getMin
-- etc.
4

2 に答える 2

6

Monoid正確に正しいことを行うインスタンスがあります:

instance Monoid a => Monoid (Maybe a) where
  mempty = Nothing
  Nothing `mappend` m = m
  m `mappend` Nothing = m
  Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)

ですData.Monoid

したがって、

foldMap (liftA Sum) [Just 1, Nothing, Just 2, Nothing, Just 3] = 
   fold [Just (Sum 1), Nothing, Just (Sum 2), Nothing, Just (Sum 3)] = 
      Just (Sum 6)

厳密な左折バージョンでは、代わりにをfold使用できfoldl' mappend mempty、代わりに をfoldMap f使用できますfoldl' (mappend . f) memptyMaybeモノイドでは、memptyですNothing

于 2016-10-06T10:22:01.930 に答える