packages feed

testing-feat-1.1.1.1: examples/lambda-terms/lambdas.hs

-- This module contains an enumeration of well scoped lambda terms
{-# LANGUAGE DeriveDataTypeable #-}

import Test.Feat.Enumerate
import Control.Enumerable
import Test.Feat.Access
import Test.Feat

-- Shows off a bit
main = do
  putStr "There are this many closed lambda terms with 100 lambdas/applications: "
  let n = count 100
  print n
  putStr   $ "Here is one of them: " 
  putStrLn $ pretty (selectTerm 100 (n `div` 2))
  putStrLn "Here are all the terms of size 3:"
  mapM_ (putStrLn . pretty) (snd $ vs !! 3)


data Term scope  = Lam (Term (FinS scope))
                 | App (Term scope) (Term scope)
                 | Var scope
                 deriving (Show, Typeable)
instance Enumerable a => Enumerable (Term a) where
  enumerate  = share $ aconcat 
                 [ c1 Var   -- Variables are size 0, add pay to make size 1
                 , pay (c1 Lam) -- "Irregular constructor"
                 , pay (c2 App)]

-- Finite numeric types
data FinZ deriving Typeable
instance Show FinZ where
  show _ = undefined
instance Enumerable FinZ  where
  enumerate = datatype []
data FinS n = Z | S n deriving (Typeable, Show)
instance Enumerable n => Enumerable (FinS n) where
  enumerate = share $ aconcat [c0 Z, c1 S]

-- All closed lambda expressions
closed = global :: Enumerate (Term FinZ)
vs = valuesWith closed

-- Count the number of terms of a given size
count n = fst $ vs !! n

-- Select any term of a given size
selectTerm = selectWith closed








-- The rest is just pretty-printing stuff
pretty :: Fin a => Term a -> String
pretty t = prettyPar 0 0 t where
    -- p: 0-never 1-lambda 2-always
    prettyPar :: Fin a => Int -> Int -> Term a -> String
    prettyPar _ _ (Var s) = "x"++show (toInt s)
    prettyPar n p (Lam t) = par 1 p $ "\\x"++show n++"->"++prettyPar (n+1) 0 t
    prettyPar n p (App t1 t2) = par 2 p $
      prettyPar n 1 t1 ++ " " ++ prettyPar n 2 t2
    par p p' s = if p <= p' then "(" ++ s ++ ")" else s

class Fin a where
  toInt :: a -> Int

instance Fin FinZ where
  toInt a = a `seq` error "toInt FinZ"

instance Fin n => Fin (FinS n) where
  toInt Z     = 0
  toInt (S n) = toInt n + 1