計算機科学のブログ

コンテキストでの型の操作 do表記を使ってMonadを扱いやすくする do表記、糖衣構文、脱糖、>>=、>>、return、ラムダ式

入門Haskellプログラミング (Will Kurt(著)、株式会社クイープ(監修、翻訳)、翔泳社)のUNIT5(コンテキストでの型の操作)、LESSON 31(do表記を使ってMonadを扱いやすくする)、31.4(練習問題)Q31-1の解答を求めてみる。

コード

lesson/app/Main.hs

module Main (main) where

import Lib
  ( comparePizzas,
    describePizza,
  )

main :: IO ()
main =
  return
    "What is the size of pizza 1"
    >>= putStrLn
    >> getLine
    >>= ( \size1 ->
            return
              "What is the cost of pizza 1"
              >>= putStrLn
              >> getLine
              >>= ( \cost1 ->
                      return
                        "What is the size of pizza 2"
                        >>= putStrLn
                        >> getLine
                        >>= ( \size2 ->
                                return
                                  "What is the cost of pizza 2"
                                  >>= putStrLn
                                  >> getLine
                                  >>= ( \cost2 ->
                                          ( \pizza1 ->
                                              ( \pizza2 ->
                                                  ( \betterPizza ->
                                                      return
                                                        ( describePizza
                                                            betterPizza
                                                        )
                                                        >>= putStrLn
                                                  )
                                                    ( comparePizzas
                                                        pizza1
                                                        pizza2
                                                    )
                                              )
                                                ( read size2,
                                                  read cost2
                                                )
                                          )
                                            ( read size1,
                                              read cost1
                                            )
                                      )
                            )
                  )
        )

lesson/src/Lib.hs

module Lib
  ( describePizza,
    comparePizzas,
  )
where

type Pizza = (Double, Double)

costPerInch :: Pizza -> Double
costPerInch (size, cost) = cost / areaGivenDiameter size

areaGivenDiameter :: Double -> Double
areaGivenDiameter size = pi * (size / 2) ** 2

describePizza :: Pizza -> String
describePizza (size, cost) =
  mconcat
    [ "The ",
      show size,
      " pizza is cheaper at ",
      show (costPerInch (size, cost)),
      " per square inch"
    ]

comparePizzas :: Pizza -> Pizza -> Pizza
comparePizzas p1 p2 =
  if costPerInch p1 < costPerInch p2
    then p1
    else p2

入出力結果(Terminal, Zsh)

% stack exec lesson-exe
What is the size of pizza 1
5
What is the cost of pizza 1
10
What is the size of pizza 2
10
What is the cost of pizza 2
5
The 10.0 pizza is cheaper at 6.366197723675814e-2 per square inch
% stack exec lesson-exe
5
What is the size of pizza 1
What is the cost of pizza 1
1
What is the size of pizza 2
10
What is the cost of pizza 2
5
The 5.0 pizza is cheaper at 5.092958178940651e-2 per square inch
%