Rodney
Rodney

Reputation: 205

Pure Lambda Calculus - and function

I am currently learning Haskell and also participating in a rather theoretical lecture about functional programming at university.

I know that this is purely theoretical/academic question, but nevertheless I am interested how to express different simple functions simply with pure lambda calculus (i.e. without any constants defined).

Some lecture materials of mine define the boolean values such as:

True = \xy.x
False = \xy.y

(\ denoting the lambda symbol)

If they are defined like these selector functions, the if-condition can be easily defined as:

If = \x.x

Now, I'm trying to come up with some short form for the logical "and"-function. My first guess is:

and = \xy.{(If x)[(If y) True False] False}

So basically this lambda function would receive 2 arguments u v where both have to be typed like True/False. If I do various beta-reductions with all 4 combinations of the logic table I receive the right result.

Nevertheless this function looks a little ugly and I'm thinking about making it more elegant. Any proposals here?

Upvotes: 8

Views: 1280

Answers (3)

J. Abrahamson
J. Abrahamson

Reputation: 74344

We can just do reductions on your answer to get a pithier one.

First some warm-ups. Obviously IF x ==> x, and as TRUE TRUE FALSE ==> TRUE and FALSE TRUE FALSE ==> FALSE if x is a boolean then x TRUE FALSE ==> x.

Now we reduce

\x y . (IF x) ( (IF y) TRUE FALSE ) FALSE
\x y .     x  (     y  TRUE FALSE ) FALSE  -- using IF x         ==> x
\x y .     x  (     y             ) FALSE  -- using y TRUE FALSE ==> y
\x y . x y FALSE                           -- clean up

and this expression still works with truth tables

AND TRUE  TRUE  = TRUE  TRUE  FALSE = TRUE
AND FALSE TRUE  = FALSE TRUE  FALSE = FALSE
AND TRUE  FALSE = TRUE  FALSE FALSE = FALSE
AND FALSE FALSE = FALSE FALSE FALSE = FALSE

Upvotes: 11

Riccardo T.
Riccardo T.

Reputation: 8937

Church's booleans, right? :) I developed for fun a small module by using the RankNTypes feature in order to represent them as close to the original Lambda calculus version as possible.

So, if you enable RankNTypes:

{-# LANGUAGE RankNTypes #-}

You might represent the type of Church booleans as the functions a -> a -> a for any type a, thus having a compact representation for True and False very similar to yours. The typing here will allow us to compose the functions more freely, though.

type CBool = forall a. a -> a -> a

ctrue :: CBool
ctrue t f = t

cfalse :: CBool
cfalse t f = f

Now, how is a conjunction written in these terms? Let's say you have a left operand l and a right operand r which are both CBool, that is, functions a -> a -> a which either return you the first or the second parameter depending on whether it's ctrue or cfalse. You can evaluate this function by giving in input r as the first parameter and l itself as the third. If l is ctrue, then it will evaluate to its first parameter, which is r: should it be ctrue again, then our conjunction is satisfied. In any other case, cfalse will be returned.

cand :: CBool -> CBool -> CBool
cand l r = l r l

The disjunction can be represented in a similar way, with the same trick of directly evaluating the functions representing booleans given in input. Except that here you'll swap the two arguments for evaluating l: if l is ctrue, it will return l itself otherwise it is all up to r's value

cor :: CBool -> CBool -> CBool
cor l r = l l r

By enabling RankNTypes, I think this is the closest as you can get to the original definitions of conjunction and disjunction for Church's boolean numbers in Lambda Calculus. I also wrote functions to translate back and forth from regular Bool and CBool, the negation, and also Church's natural numbers with the same style. You can find the whole source code at https://github.com/rtraverso86/haskkit/blob/master/Haskkit/Data/Church.hs.

Upvotes: 3

luqui
luqui

Reputation: 60463

Well, and True is the identity function, and and False is the constant function returning False, so we can use that.

and = \x. if x id (const False)

which has a nice symmetry with

or = \x. if x (const True) id

(where

id = \x. x
const = \x y. x

)

The common pattern for eliminators takes the data at the end of the argument list which often works elegantly with pointfree style, so if you defined:

cond = \t f b. b t f

then you could express

and = cond id (const False)
or  = cond (const True) id

which is the best I've got. There are probably yet more elegant formulations by viewing bools in cool ways.

Upvotes: 4

Related Questions