値が欠落しているデータを扱っています。これは、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.