Write You a Programming language for Computable Functions: Syntax

This post is the first one in a series where I will walk through the implementation of an untyped version of PCF1 in Haskell.

I will extend the original PCF with constant naturals, the basic arithmetic operations \(+, -, \times, /\), a list datatype with the primitive functions cons, head, tail and null. In addition, I add let ... in ... and let rec ... in ... constructs as syntactic sugar.

The complete source code is available on github. The structure of the project closely follows Write You a Scheme. The inside is inspired by Stephen Diehl’s Write You a Haskell.

In this post I will describe the AST of my implementation.

Here is a description of the original PCF without its types in the BNF formalism:

$$ \begin{align} \langle Expr \rangle ::=&\ 0\ |\ true\ |\ false \\
&|\ \langle var \rangle \\
&|\ succ( \langle Expr \rangle ) \
|\ pred( \langle Expr \rangle ) \
|\ iszero( \langle Expr \rangle ) \\
&|\ if\ \langle Expr \rangle\
then\ \langle Expr \rangle\
else\ \langle Expr \rangle \\
&|\ \langle Expr \rangle\ \langle Expr \rangle \\
&|\ \lambda \langle var \rangle . \langle Expr \rangle \\
&|\ \mu \langle var \rangle . \langle Expr \rangle \end{align} $$

In PCF, the numbers are the non-negative integers and are built from the constructor \(0\) and the combinators \(pred\) and \(succ\). Conditional expressions are represented here by the \(if … then … else …\) construct. The expression after \(if\) must evaluate to one of the constructors \(true\) or \(false\). In case of \(true\), the entire conditional expression has the same result as the expression that follows \(then\), otherwise its result is that of the expression that follows \(else\). Function abstraction and application have the same shape as in the lambda calculus. And recursion is expressed with the \(\mu\) operator. Using the fixpoint operator, this expression for recursion can be written as \( Fix(\lambda \langle var \rangle . \langle Expr \rangle)\).

In my implementation, numbers are the inhabitants of Haskell’s Integer type. The boolean constructors \(true\) and \(false\) are from Haskell’s Bool type. Lists of PCF expressions are formed with the help of Haskell’s List. Without forgetting the binary operators, these considerations lead us to the following Haskell representation

data Expr
  = Var String
  | Nat Integer
  | Bool Bool
  | List [Expr]
  | App Expr Expr
  | Lam String Expr
  | Mu String Expr
  | If Expr Expr Expr
  | PrimOp PrimOp Expr
  | Op BinOp Expr Expr
  | Undefined
  deriving (Show, Eq)

data PrimOp
  = Succ
  | Pred
  | IsZero
  deriving (Show, Eq)

data BinOp
  = Add
  | Sub
  | Mult
  | Div
  deriving (Show, Eq)

That is all we need to represent the version of PCF I want to present. In the next post I will describe the parsing of text into this AST.

Bibliography


  1. LCF Considered as a programming language, G.D Plotkin ↩︎


haskell

483 Words

2022-10-11 07:17 +0900