diff options
author | Ben Sima <ben@bsima.me> | 2018-08-07 15:32:21 -0700 |
---|---|---|
committer | Ben Sima <ben@bsima.me> | 2018-08-07 15:32:21 -0700 |
commit | 65425cf618f348ed89e9d07706fa28338f84f0b5 (patch) | |
tree | 7753b944a9d6d074836c709dfe2ab405c930940d /ski.hs | |
parent | 6db87806aadc680edaa37a0143a60525629b660e (diff) |
Add ski calculus interpretor
Diffstat (limited to 'ski.hs')
-rwxr-xr-x | ski.hs | 70 |
1 files changed, 70 insertions, 0 deletions
@@ -0,0 +1,70 @@ +#! /usr/bin/env nix-shell +#! nix-shell -p haskellPackages.ghc -i runghc + +{-# OPTIONS_GHC -Wall #-} + +-- An expression in the SKI calculus is either S, K, I, or an application Ap of +-- any of 2 those combinators together. +data Expr + = S + | K + | I + | Ap Expr Expr + deriving (Show, Eq) + +-- The eval function is the only function we need. It takes an expression and +-- returns an expresison. + +eval :: Expr -> Expr + +-- First define the S combinator. We evaluate in a strict fashion, from the left +-- to the right, so the placement of the parens must reflect this order of +-- operations. + +eval S = S +eval (Ap (Ap (Ap S x) y) z) = eval (Ap (Ap x z) (Ap y z)) +eval (Ap S x) = Ap S (eval x) + +-- K and I combinators are simpler: + +eval K = K +eval (Ap (Ap K x) _) = eval x +eval (Ap K x) = Ap K (eval x) + +eval I = I +eval (Ap I x) = eval x + +-- One benefit of doing this in Haskell is the compiler can do exaustive pattern +-- checking for us to make sure that we've covered every combination of S, K, +-- and I possible in our little language defined by 'Expr'. +-- +-- In this case, the compiler warns that we don't have a case for +-- +-- (Ap (Ap _ _) _) +-- +-- so we just define that by recursing onto each branch of the Expr tree. But +-- first we check for branch equality, to avoid infinite recursion: +-- +eval (Ap a b) = + if a == a' && b == b' + then (Ap a b) + else eval (Ap a' b') + where + a' = eval a + b' = eval b + +-- Some example tests: +main :: IO () +main = do + putStrLn $ "Expect I: " ++ show i + putStrLn $ "Expect K: " ++ show k + putStrLn $ "Expect K: " ++ show s + putStrLn $ "Expect S: " ++ show kiss + putStrLn $ "Expect SKSISKKI: " ++ show a + where + i = eval (Ap I I) -- I I = I + k = eval (Ap (Ap K K) I) -- K K I = K + s = eval (Ap (Ap (Ap S K) S) K) -- S K S K = K K (S K) = K + -- (S (K (S I)) (S (K K) I)) + a = eval (Ap (Ap S (Ap K (Ap S I))) (Ap (Ap S (Ap K K)) I)) + kiss = eval (Ap (Ap (Ap K I) S) S) |