Skip to content

bellissimogiorno/nominal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nominal

Basic information

The interaction of name-binding and alpha-equivalence with data can be tricky. Examples include:

  • Inductively defining syntax and reductions of a syntax with binding, e.g. lambda-calculus or System F.
  • Graph-like structures, especially if they have danging pointers.

This package implements a nominal datatypes package in Haskell, based on names and swappings.
With it, you can define data with name-binding and program on this data in a manner closely mirroring informal practice.

The package design is based on a well-studied mathematical reference model as described in a new approach to abstract syntax with variable binding (author's pdfs).

For usage, please see:

Building and running

Clone this repo:

    $ git clone https://github.com/bellissimogiorno/nominal.git
    $ cd nominal

Using Stack

  1. Install Stack.

  2. Build:

     $ stack build
    
  3. Read the documentation:

     $ stack haddock --open
    
  4. Run some unit- and property-based tests:

     $ stack test
    
  5. Explore it in ghci:

     $ stack ghci src/Language/Nominal/Examples/SystemF.hs
     $ stack ghci src/Language/Nominal/Examples/IdealisedEUTxO.hs
    

Using Cabal

  1. Install Cabal.

  2. Build:

     $ cabal build
    
  3. Read the documentation:

     $ cabal haddock
    

    This will build the documentation and output the name of the html-file that you can then open in your browser.

  4. Run some unit- and property-based tests:

     $ cabal test --test-show-detail=direct
    
  5. Explore it in ghci:

     $ cabal repl Language/Nominal/Examples/SystemF.hs
     $ cabal repl Language/Nominal/Examples/IdealisedEUTxO.hs
    

Example

Copied from the untyped lambda calculus example, and see a corresponding example from the Bound package.

{-# LANGUAGE InstanceSigs
           , DeriveGeneric
           , LambdaCase
           , MultiParamTypeClasses
           , DeriveAnyClass       -- to derive 'Swappable'
           , DeriveDataTypeable   -- to derive 'Data'
           , FlexibleInstances
#-}


module Language.Nominal.Examples.UntypedLambda
    (
     Var, Exp (..), whnf, lam, example1, example1whnf, example2, example2whnf
    )
    where

import GHC.Generics
import Data.Generics     hiding (Generic, typeOf)

import Language.Nominal.Utilities
import Language.Nominal.Name
import Language.Nominal.Nom
import Language.Nominal.Abs
import Language.Nominal.Sub

-- | Variables are string-labelled names
type Var = Name String

infixl 9 :@
-- | Terms of the untyped lambda-calculus
data Exp = V Var              -- ^ Variable
         | Exp :@ Exp         -- ^ Application
         | Lam (KAbs Var Exp) -- ^ Lambda, using abstraction-type
 deriving (Eq, Generic, Data, Swappable, Show)

-- | helper for building lambda-abstractions
lam :: Var -> Exp -> Exp
lam x a = Lam (x @> a)

-- | Substitution.  Capture-avoidance is automatic.
instance KSub Var Exp Exp where
   sub :: Var -> Exp -> Exp -> Exp
   sub v t = rewrite $ \case -- 'rewrite' comes from Scrap-Your-Boilerplate generics.  It goes automatically under the binder.
      V v' | v' == v -> Just t   -- If @V v'@, replace with @t@ ...
      _              -> Nothing  -- ... otherwise recurse.

{- The substitution instance above is equivalent to the following:

-- | Explicit recursion.
expRec :: (Var -> a) -> (Exp -> Exp -> a) -> (Var -> Exp -> a) -> Exp -> a
expRec f0 _ _ (V n)      = f1 n
expRec _ f1 _ (s1 :@ s2) = f2 s1 s2
expRec _ _ f2 (Lam x')   = f3 `genApp` x'

instance KSub Var Exp Exp where
   sub :: Var -> Exp -> Exp -> Exp
   sub v t = expRec (\v'   -> if v' == v then t else V v')
                    (\a b  -> sub v t a :@ sub v t b)
                    (\v' a -> lam v' $ sub v t a)
-}

-- | weak head normal form of a lambda-term.
whnf :: Exp -> Exp 
whnf (Lam b' :@ a) = whnf $ b' `conc` a  
whnf             e = e

-- | (\x x) y
example1 :: Exp
example1 = (\[x, y] -> lam x (V x) :@ V y) `genAppC` freshNames ["x", "y"] 
-- | y
example1whnf :: Exp
example1whnf = whnf example1

-- | (\x xy) x
example2 :: Exp
example2 = (\[x, y] -> lam x (V x :@ V y) :@ V x) `genAppC` freshNames ["x", "y"] 
-- | xy
example2whnf :: Exp
example2whnf = whnf example2

Acknowledgements

Thanks to Lars Brünjes for help, support, and code contributions.

About

Haskell implementation of nominal datatypes and functions

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published