はじめに

Data.MonoidDual 型が定義されています。

newtype Dual a = Dual { getDual :: a }

instance Semigroup a => Semigroup (Dual a) where
  Dual a <> Dual b = Dual (b <> a)

instance Monoid a => Monoid (Dual a) where
  mempty = Dual mempty

使い方は簡単。

ghci> getDual $ Dual "aaa" <> mempty <> Dual "bbb"
"bbbaaa"

ghci> getDual $ foldMap Dual ["aaa", "bbb"]
"bbbaaa"

いつか使う時もあるかもしれないので、適当な例を作ってみます。

Semigroup, Monoid law の確認

Semigroup Law

  Dual a <> (Dual b <> Dual c)
= Dual a <> Dual (c <> b)
= Dual ((c <> b) <> a)
-- a, b, c は Semigroup なので
= Dual (c <> (b <> a))
= Dual (b <> a) <> Dual c
= (Dual a <> Dual b) <> Dual c

Monoid Law

  Dual a <> (mempty :: Dual a)
= Dual a <> Dual (mempty :: a)
= Dual ((mempty :: a) <> a)
-- a は Monoid なので
= Dual a

  (mempty :: Dual a) <> Dual a
= Dual (mempty :: a) <> Dual a
= Dual (a <> (mempty :: a))
-- a は Monoid なので
= Dual a

headMaybe

headMaybe :: [a] -> Maybe a
headMaybe = getLast . getDual . foldMap (Dual . Last . pure)

-- First を使った定義
headMaybe :: [a] -> Maybe a
headMaybe = getFirst . foldMap (First . pure)
ghci> headMaybe []
Nothing

ghci> headMaybe "abcd"
Just 'a'

lastMaybe

lastMaybe :: [a] -> Maybe a
lastMaybe = getFirst . getDual . foldMap (Dual . First . pure)

-- Last を使った定義
lastMaybe :: [a] -> Maybe a
lastMaybe = getLast . foldMap (Last . pure)
ghci> lastMaybe []
Nothing

ghci> lastMaybe "abcd"
Just 'd'

last

last' :: [a] -> a
last' = getAlt . getDual . foldMap (Dual . Alt . pure)
ghci> last []
*** Exception: user error (mzero)

ghci> last "abc"
'c'

reverse

rev :: [a] -> [a]
rev = getDual . foldMap (Dual . pure)
ghci> rev [5,2,4,7]
[7,4,2,5]

ghci> rev "Hello World"
"dlroW olleH"

foldl

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z

参考