DEV Community

Discussion on: Daily Challenge #111 - 99 Bottles of Beer

Collapse
 
jbristow profile image
Jon Bristow

This is as close as I can get to “no string declared more than once”

module Beer
  ( song
  ) where

import qualified Data.Char as Char
import qualified Data.List as List

bottlesOfBeer :: Int -> String
bottlesOfBeer n = " bottle" ++ plural ++ " of beer"
  where
    plural =
      case n of
        1 -> ""
        _ -> "s"

onTheWall :: Int -> String
onTheWall n = howMany n ++ " on the wall"

howMany :: Int -> String
howMany n = countStr ++ bottlesOfBeer n
  where
    countStr =
      case n of
        0 -> "no more"
        _ -> show n

capitalize :: String -> String
capitalize (h:r) = Char.toUpper h : r

line2start :: Int -> String
line2start 0 = "Go to the store and buy some more"
line2start n = "Take " ++ theOne ++ " down and pass it around"
  where
    theOne =
      case n of
        1 -> "it"
        _ -> "one"

next 0 = 99
next n = pred n

outputLine :: [Int -> String] -> Int -> String
outputLine fs = List.intercalate ", " . sequence fs

verse :: Int -> String
verse =
  List.intercalate "" .
  map (++ ".\n") .
  mapM
    outputLine
    [[capitalize . onTheWall, howMany], [line2start, onTheWall . next]]

song :: String
song = List.intercalate "\n" $ map verse [99,98 .. 0]