Advertisement
NLinker

Haskell solution to the Smile problem

Jul 13th, 2016
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- from here
  2. -- https://www.quora.com/Homework-Question-How-do-I-write-a-program-that-produces-the-following-output-1#
  3.  
  4.     -- This is a nice problem that we can write a very easy
  5.     -- piece of Haskell code for to demonstrate its simplicity!
  6.      
  7.     -- First, we need Peano numbers so that we can count things.
  8.     -- Always define your own, never trust the built-in integers!
  9.      
  10.     data Nat = Zero | Succ Nat
  11.       deriving (Eq, Show)
  12.      
  13.     -- Now I will set the ground work for the rest of our program.
  14.     -- This is a pretty obvious and self-explanatory data type.
  15.     -- We will use it to create a stream of functors that ends in a Pure constructor.
  16.      
  17.     data Free f r = Free (f (Free f r)) | Pure r
  18.      
  19.     -- We need our enriched data type to be a Functor if the base type is a Functor.
  20.     -- If you don't know what a Functor is, just think of a Functor F from category X
  21.     -- to category Y as something that maps every x in X to an F(X) in Y, and every morphism f
  22.     -- to F(f) :: F(A) -> F(B). Importantly, it must preserve idenity and composition of morphisms,
  23.     -- ie forall morphisms f :: A -> B in X we have F(id_A) = id_{F_A} and F ( g . f) = F g . F f
  24.     -- It's very easy when you think about.
  25.      
  26.     instance Functor f => Functor (Free f) where
  27.       fmap g (Pure a)  = Pure $ g a
  28.       fmap g (Free f) = Free ((g <$>) <$> f)
  29.      
  30.     -- We will need this because Applicative is a superclass of Monad in the
  31.     -- newest Haskell spec.
  32.      
  33.     instance Functor f => Applicative (Free f) where
  34.       pure = Pure
  35.       Pure f <*> x = f <$> x
  36.       Free ma <*> b = Free $ (<*> b) <$> ma
  37.      
  38.     -- From the library definition, "a Monad n is a free Monad for f if every
  39.     -- monad homomorphism from n to another monad m is equivalent to a natural
  40.     -- transformation from f to m."
  41.      
  42.     instance (Functor f) => Monad (Free f) where
  43.       return = Pure
  44.       (Free x) >>= f = Free (fmap (>>= f) x)
  45.       (Pure r) >>= f = f r
  46.      
  47.     -- Lifting from a normal functor f to Free f will be handy
  48.      
  49.     liftF :: (Functor f) => f r -> Free f r
  50.     liftF = Free . fmap Pure
  51.      
  52.     -- We are done with the pre-requisite definitions.
  53.     -- We can now define a custom DSL to represent our language of smiling.
  54.      
  55.     data SmileExpr r e = Smile r Nat e | Line e | Done
  56.       deriving (Eq, Show)
  57.      
  58.     -- We are future proofing our program so it will work with arbitrary
  59.     -- smiling types.
  60.      
  61.     data SmileType = CapitalSmile deriving (Eq)
  62.      
  63.     instance Show SmileType where
  64.       show CapitalSmile = "Smile!"
  65.      
  66.     -- Trivial Functor intsance for our smile language. We of course need
  67.     -- this as our intepreter won't work without a Functor instance.
  68.      
  69.     instance Functor (SmileExpr r) where
  70.       fmap f (Done) = Done
  71.       fmap f (Line e) = Line $ f e
  72.       fmap f (Smile t n e) = Smile t n (f e)
  73.      
  74.     -- Lifted helpers to write in our language
  75.      
  76.     smile t n = liftF $ Smile t n ()
  77.     done = liftF Done
  78.     line = liftF (Line ())
  79.      
  80.     -- Helper to construct our smiling "tower" per the spec.
  81.     -- What I hope you'll appreciate is that this is still a
  82.     -- pure data representation of our smile language.
  83.      
  84.     downFrom :: SmileType -> Nat -> Free (SmileExpr SmileType) r
  85.     downFrom t (Succ n) = smile t (Succ n) >> line >> downFrom t n
  86.     downFrom _ Zero = done
  87.      
  88.     -- Now the interpreter for our DSL. As you can see you can now write arbitrary
  89.     -- interpreters for our language. I encourage you to play with it!
  90.      
  91.     interpret :: (Show r) => Free (SmileExpr r) k -> IO ()
  92.     interpret (Free Done) = return ()
  93.     interpret (Free (Line e)) = putStrLn "" >> interpret e
  94.     interpret (Free (Smile t (Succ n) e)) = putStr (show t) >> interpret (Free (Smile t n e))
  95.     interpret (Free (Smile _ Zero e)) = interpret e
  96.      
  97.     -- Now to demonstrate how our interpreter works.
  98.      
  99.     -- Peano representation of the concept of 'three'.
  100.     -- I leave it as exercise to the reader to generalize this.
  101.     sssz = Succ (Succ (Succ Zero))
  102.      
  103.     -- We are done! Run the program.
  104.     run :: IO ()
  105.     run = interpret $ downFrom CapitalSmile sssz
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement