Skip to content

Instantly share code, notes, and snippets.

@rewinfrey
Created May 26, 2017 21:34
Show Gist options
  • Save rewinfrey/31e5aa1b9f90d5ad6dced41d11cbb714 to your computer and use it in GitHub Desktop.
Save rewinfrey/31e5aa1b9f90d5ad6dced41d11cbb714 to your computer and use it in GitHub Desktop.
Recursion Schemes in Haskell
#!/usr/bin/env stack
-- stack --resolver lts-8.12 script
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TypeFamilies #-}
import qualified Data.Text as T
import ClassyPrelude
import Data.Functor.Foldable
data Expr a
= NumLit Int
| Add a a
| Div a a
deriving (Show, Functor)
type ExprF = Fix Expr
type instance Base (Fix Expr) = Expr
litExpr :: Int -> ExprF
litExpr = Fix . NumLit
addExpr :: ExprF -> ExprF -> ExprF
addExpr a b = Fix $ Add a b
divExpr :: ExprF -> ExprF -> ExprF
divExpr a b = Fix $ Div a b
exprEvaluatorCata :: ExprF -> Int
exprEvaluatorCata = cata algebra
where
algebra :: Expr Int -> Int
algebra expr = case expr of
NumLit a -> a
(Add a b) -> a + b
(Div a b) -> a `ClassyPrelude.div` b
main :: IO ()
main = do
let lit' = litExpr 5
print $ exprEvaluatorCata lit'
let add' = addExpr lit' (litExpr 15)
print $ exprEvaluatorCata add'
let div' = divExpr (litExpr 40) (litExpr 20)
print $ exprEvaluatorCata div'
let mixedExpression = divExpr add' div' -- equivalent to: (5 + 15) / (40 / 20) => 20 / 2 => 10
print $ exprEvaluatorCata mixedExpression
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment