packages feed

distributors-0.4.0.0: test/Examples/Lambda.hs

module Examples.Lambda
  ( Lambda (..)
  , lambdaGrammar
  , lambdaExamples
  ) where

import Control.Lens
import Control.Lens.Grammar

-- | Abstract syntax tree for lambda calculus terms
data Lambda
  = Var String           -- ^ Variable
  | Lam String Lambda    -- ^ Lambda abstraction (\\x.body)
  | App Lambda Lambda    -- ^ Function application
  deriving stock (Eq, Ord, Show, Read)

-- Generate prisms
makePrisms ''Lambda

-- | Grammar for untyped lambda calculus
lambdaGrammar :: Grammar Char Lambda
lambdaGrammar = ruleRec "lambda" termG
  where
    -- Top level term: lambda abstraction or application
    termG term = rule "term" $ choice
      [ lamG term
      , appG term
      ]

    -- Lambda abstraction: \x.body
    lamG term = rule "lambda" $
      _Lam >? terminal "\\" >* varNameG *< terminal "." >*< term

    -- Application: left-associative chain of atoms
    -- e.g., "f x y" parses as "(f x) y"
    appG term = rule "application" $
      chain1 Left _App (sepWith " ") (atomG term)

    -- Atomic term: variable or parenthesized term
    atomG term = rule "atom" $ choice
      [ _Var >? varNameG
      , terminal "(" >* term *< terminal ")"
      ]

    -- Variable name: starts with lowercase letter,
    -- followed by alphanumeric or underscore
    varNameG = rule "varname" $ asIn LowercaseLetter >:<
      manyP (choice (token '_' : map asIn [LowercaseLetter, UppercaseLetter, DecimalNumber]))

-- | Example lambda calculus terms for testing
lambdaExamples :: [(Lambda, String)]
lambdaExamples =
  -- Variables
  [ (Var "x", "x")
  , (Var "y", "y")
  , (Var "foo", "foo")
  , (Var "x1", "x1")

  -- Simple lambda abstractions
  , (Lam "x" (Var "x"), "\\x.x")                        -- Identity
  , (Lam "x" (Lam "y" (Var "x")), "\\x.\\y.x")          -- K combinator
  , (Lam "x" (Lam "y" (Var "y")), "\\x.\\y.y")          -- K* combinator

  -- Applications
  , (App (Var "f") (Var "x"), "f x")
  , (App (App (Var "f") (Var "x")) (Var "y"), "f x y")

  -- Lambda with application in body
  , (Lam "f" (Lam "x" (App (Var "f") (Var "x"))),
     "\\f.\\x.f x")

  -- S combinator: \x.\y.\z.x z (y z)
  , (Lam "x" (Lam "y" (Lam "z"
      (App (App (Var "x") (Var "z"))
           (App (Var "y") (Var "z"))))),
     "\\x.\\y.\\z.x z (y z)")

  -- Omega combinator: (\x.x x)(\x.x x)
  , (App (Lam "x" (App (Var "x") (Var "x")))
         (Lam "x" (App (Var "x") (Var "x"))),
     "(\\x.x x) (\\x.x x)")

  -- Church numeral 0: \f.\x.x
  , (Lam "f" (Lam "x" (Var "x")),
     "\\f.\\x.x")

  -- Church numeral 1: \f.\x.f x
  , (Lam "f" (Lam "x" (App (Var "f") (Var "x"))),
     "\\f.\\x.f x")

  -- Church numeral 2: \f.\x.f (f x)
  , (Lam "f" (Lam "x"
      (App (Var "f") (App (Var "f") (Var "x")))),
     "\\f.\\x.f (f x)")

  -- Y combinator: \f.(\x.f (x x)) (\x.f (x x))
  , (Lam "f"
      (App (Lam "x" (App (Var "f") (App (Var "x") (Var "x"))))
           (Lam "x" (App (Var "f") (App (Var "x") (Var "x"))))),
     "\\f.(\\x.f (x x)) (\\x.f (x x))")
  ]