計算機科学のブログ

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

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

コード

lesson/app/Main.hs

module Main where

import Lib

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

probs :: Probs
probs = Probs [0.5, 0.5]

main :: IO ()
main = do
  print $ events <> events
  print $ probs <> probs

lesson/src/Lib.hs

module Lib where

data Events = Events [String] deriving (Show)

instance Semigroup Events where
  (<>) (Events xs) (Events ys) =
    Events $ cartCombine (\x y -> mconcat [x, "-", y]) xs ys

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

data Probs = Probs [Double] deriving (Show)

instance Semigroup Probs where
  (<>) (Probs xs) (Probs ys) =
    Probs $ cartCombine (*) xs ys

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

cartCombine :: (a -> b -> c) -> [a] -> [b] -> [c]
cartCombine func l1 l2 =
  let nToAdd = length l2
      repeatedL1 = map (replicate nToAdd) l1
      newL1 = mconcat repeatedL1
      cycledL2 = cycle l2
   in zipWith func newL1 cycledL2

入出力結果(Terminal, Zsh)

% stack exec lesson-exe
Events ["heads-heads","heads-tails","tails-heads","tails-tails"]
Probs [0.25,0.25,0.25,0.25]
%