Last active
October 26, 2020 02:27
-
-
Save coord-e/bb803f8d365f71c1b8a8dc0ca6aa1a39 to your computer and use it in GitHub Desktop.
キッチン計算
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env stack | |
-- stack --resolver lts-16.5 script --package mtl | |
{-# LANGUAGE NamedFieldPuns #-} | |
{-# LANGUAGE DerivingStrategies #-} | |
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
import Numeric.Natural ( Natural ) | |
import Data.List ( genericReplicate | |
, genericLength | |
) | |
import Control.Monad ( when ) | |
import Control.Monad.State ( MonadState | |
, State | |
, modify | |
, gets | |
, runState | |
) | |
whileM :: Monad m => m Bool -> m () | |
whileM act = do | |
b <- act | |
when b $ whileM act | |
data Plate | |
= CleanPlate | |
| UsedPlate | |
-- | Datatype representing kitchen's state | |
data Kitchen | |
= Kitchen | |
{ plates :: [Plate] | |
} | |
-- | Computation that runs on kitchen | |
newtype KitchenM a = KitchenM (State Kitchen a) | |
deriving newtype (Functor, Applicative, Monad) | |
deriving newtype (MonadState Kitchen) | |
-- | Obtain kitchen containing specified number of plates | |
kitchen :: Natural -> Kitchen | |
kitchen n = Kitchen { plates } | |
where | |
plates = genericReplicate n CleanPlate | |
-- | Run 'KitchenM' within specified number of plates | |
runKitchen :: Natural -> KitchenM a -> (a, Natural) | |
runKitchen numberOfPlates (KitchenM m) = (a, genericLength plates) | |
where (a, Kitchen { plates }) = runState m (kitchen numberOfPlates) | |
-- | Is the kitchen clean? | |
isClean :: Kitchen -> Bool | |
isClean Kitchen { plates } = null plates | |
-- | Wash one plate | |
wash :: KitchenM () | |
wash = modify $ f . plates | |
where | |
f (CleanPlate:rest) = f rest | |
f (UsedPlate:rest) = Kitchen { plates = rest } | |
f [] = Kitchen { plates = [] } | |
-- | Wash all plates | |
washAll :: KitchenM () | |
washAll = whileM $ wash *> gets (not . isClean) | |
main :: IO () | |
main = print unwashedPlates -- 0 | |
where ((), unwashedPlates) = runKitchen 10 washAll |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment