2026-09-19
Temperature.hs
findTemperature :: String -> [(String, Int)] -> Int
findTemperature city temps = case lookup city temps of
Just t -> t
Nothing -> -1
main :: IO ()
main = do
let readings = [("tokyo", 5), ("oslo", -1)]
print (findTemperature "oslo" readings)
print (findTemperature "cairo" readings)
readingsには"oslo"の気温として本物の-1(摂氏マイナス1度)が入っています。findTemperature "oslo" readingsとfindTemperature "cairo" readings(データが無い都市)を呼び分けた呼び出し元は、この2つを区別できるでしょうか?何が問題で、どう直せばよいでしょうか?
Answer
区別できません。どちらも-1を返すからです。findTemperatureは「データが無い」ことを表すのに-1という番兵値を使っていますが、気温はもともと負の値も取り得る量なので、たまたま本物の観測値として-1度が記録されている"oslo"と、データが無い"cairo"が同じ戻り値になってしまいます。番兵値は「その型が実際には取らない値」を選べるときにしか安全に使えず、気温のように定義域全体を使い切る型では安全な番兵値を選べません。Intのまま無理に番兵値を探すのではなく、「値がある」と「値がない」を型として分けているMaybe Intを使えば、この衝突は起こらなくなります:
findTemperature :: String -> [(String, Int)] -> Maybe Int
findTemperature = lookup