計算機科学のブログ

型によるプログラミング 合成によるデザイン SemigroupとMonoid データ型、リファクタリング、インスタンス

入門Haskellプログラミング (Will Kurt(著)、株式会社クイープ(監修、翻訳)、翔泳社)のUNIT3(型によるプログラミング)、LESSON 17(合成によるデザイン:SemigroupとMonoid)、17.5(練習問題)Q17-2の解答を求めてみる。

コード

data Events = Events [String] deriving Show
data Probs = Probs [Double] deriving Show

cartCombine :: (a -> b -> c) -> [a] -> [b] -> [c]
cartCombine func l1 l2 = zipWith func newL1 cycledL2
    where nToAdd = length l2
          repeatedL1 = map (take nToAdd . repeat) l1
          newL1 = mconcat repeatedL1
          cycledL2 = cycle l2

combineEvents :: Events -> Events -> Events
combineEvents (Events e1) (Events e2) = Events (cartCombine combiner e1 e2)
    where combiner = \x y -> mconcat [x, "-", y]

combineProbs :: Probs -> Probs -> Probs
combineProbs (Probs p1) (Probs p2) = Probs (cartCombine (*) p1 p2)

instance Semigroup Events where
    (<>) = combineEvents
instance Monoid Events where
    mempty  = Events []
    mappend = (<>)

instance Semigroup Probs where
    (<>) = combineProbs
instance Monoid Probs where
    mempty = Probs []
    mappend = (<>)

events1 :: Events
events1 = Events ["heads", "tails"]

events2 :: Events
events2 = Events ["red", "blue", "green"]

probs1 :: Probs
probs1 = Probs [0.5, 0.5]

probs2 :: Probs
probs2 = Probs [0.1, 0.2, 0.7]

入出力結果(Terminal, Zsh)

% ghci
GHCi, version 8.10.5: https://www.haskell.org/ghc/  :? for help
macro 'doc' overwrites builtin command.  Use ':def!' to overwrite.
(0.00 secs, 0 bytes)
(0.00 secs, 0 bytes)
Loaded GHCi configuration from /.../.ghc/ghci.conf
Prelude
λ> :load sample2
[1 of 1] Compiling Main             ( sample2.hs, interpreted )
Ok, one module loaded.
(0.14 secs,)
*Main
λ> mappend events1 events2
Events ["heads-red","heads-blue","heads-green","tails-red","tails-blue","tails-green"]
it :: Events
(0.01 secs, 137,832 bytes)
*Main
λ> mappend probs1 probs2
Probs [5.0e-2,0.1,0.35,5.0e-2,0.1,0.35]
it :: Probs
(0.01 secs, 101,632 bytes)
*Main
λ> :quit
Leaving GHCi.
%