Skip to content

Instantly share code, notes, and snippets.

@IronGremlin
Created August 2, 2017 17:17
Show Gist options
  • Save IronGremlin/eb198ac6b2716c19abcebed321af1331 to your computer and use it in GitHub Desktop.
Save IronGremlin/eb198ac6b2716c19abcebed321af1331 to your computer and use it in GitHub Desktop.
Fizzbuzz as roestta
fizzBuzzing :: [Int] -> IO () -- Function name and type signature. Says : Take an array of Int and return an IO action of (). () is pronounced 'unit', similar to Java's void.
fizzBuzzing a = -- function named fizzBuzzing with argument a is defined as...
case a of -- given a value a of
[] -> return () -- a blank list, do nothing. 'return' casts the value () as an IO (), which is necessary to type-check.
(x:xs) -> do -- for a list of the form x : xs, where x is the first item and xs is the rest of the list 'do..'
decide x -- do notation allows us to put multiple statements in a row, where the last one is the final result statement of the function. This requires the return type to implement an instance of the Monad typeclass - a more complicated subject.
fizzBuzzing xs -- the final result of calling 'fizzBuzzing' on a list of one or more items is to call fizzBuzzing on the rest of the list, xs.
where -- 'where' defines locally scoped functions. We skip[ the type signatures here because the compiller figures it out on it's own, but we could provide some if we wanted.
divBy x y = (==0) $ y `mod` x -- Partially applied infix function (==0) , becomes single arg prefix function. prefix function, mod, into an infix function, `mod` . We use '$' to force the right statement to pass it's whole result to the left.
decide n -- This is guard function syntax. The '|' character needs to be at the same column position as the first arg, on the line below (or further right). The expression to the immediate right of the '|' should return a boolean. If it's return value is True, then execute the expression to the right of the '=' symbol. The first case to return true , from top to bottom, decides the action taken.
| divBy 15 n = putStrLn "FizzBuzz" -- if n is divisible by 15, print "FizzBuzz" to console
| divBy 5 n = putStrLn "Buzz" -- by 5, print "Buzz"
| divBy 3 n = putStrLn "Fizz" -- by 3 ...
| otherwise = putStrLn . show $ n -- We terminate the guard, by convention, with 'otherwise,' which is actually just a wrapper that returns True. We could also have just said 'True.' We don't have to include an otherwise, but it acts as a default case.
-- The canonical function to spit a (not string) value at the console is 'print', but we are demonstrating the '.' and '$' operator.
-- (.) says 'make a new function with is the result of the output of the right function passed to the input of the left function. putStrLn . show is like x => { putStrLn(show(x)) } in an imperative language.'
-- But show still needs an argument to pass it's result to putStrLn. (.) only works for functions that take at least one argument. For functions that have no argument (or, just values), we use ($), which says 'apply the thing on my write to the function on my left'
-- We refer to these operators as : (.) -> Composition and ($) -> Application
-- an astute reader may note that we could just do: putStrLn (show n) - Correct. Why don't we?
-- Lets say we have 4 functions [a,b,c,d] and an argument (val) to kick it off. Here it is using (.) and ($) :
-- a . b . c . d $ val
-- Now here it is with parens:
-- a (b (c (d val)))
-- Since composing functions is a very common task in Haskell, the tree of parens would rapidly become a serious problem.
-- So, instead, we use the operators, (.) and ($)
-- Both 'operators' are just regular functions.
-- Here is their source code as defined in GHC.Base :
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x) -- \x -> is an anonymous function with one arg, x. the backslash is haskell for a lambda.
($) :: (a -> b) -> a -> b
f $ x = f x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment