Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== Lab 7. Lambda Calculus. Intro to Haskell ====== ===== 7.1 Lambda Calculus ===== **Short RECAP:** \\ Lambda Calculus represent a axiomatic system that can be used for very basic proofs. \\ Given a set of variables **VARS**, a expression under lambda calculus can be: \\ | // variable // | $ x $ | $ x \in VARS $ | | // function // | $ \lambda x.e $ | $ x \in VARS $, $ e $ is a $ \lambda $-expression | | // application // | $ (e_1 \ e_2) $ | $ e_1, e_2 $ are $ \lambda $-expressions | To evaluate $\lambda$-expressions, there are two types of reduction operations: * **$\alpha$-conversion**: given a expression: $ \lambda x.e $, you can rename all occurences of //**x**// in //**e**// with //**y**// (used for avoiding **name collisions**). * **$\beta$-reduction**: given a expression: $ \lambda x.body \ param$, you can replace all occurences of //**x**// in //**body**// with //**param**//. ==== Booleans ==== We can encode boolean values **TRUE** and **FALSE** in lambda calculus as functions that take 2 values, **x** and **y**, and return the first (for **TRUE**) or second (for **FALSE**) value. \\ $ TRUE = \lambda x.\lambda y.y$ \\ $ FALSE = \lambda x.\lambda y.x$ \\ <note>As we defined it, **TRUE** is sometimes called the **K**-Combinator (or //Kestrel//), and **FALSE** the **KI**-Combinator (or //Kite//). </note> <hidden> Some common operation on booleans (that were discussed during the lecture) are: \\ \\ $ AND = \lambda x.\lambda y.((x \ y) \ x) $ \\ $ OR = \lambda x.\lambda y.((x \ x) \ y) $ \\ $ NOT = \lambda x.((x \ FALSE) \ TRUE) $ \\ <note> **NOT** can also be written as: \\ \\ $ NOT = \lambda x.\lambda a.\lambda b.((x \ b) \ a) $ \\ \\ You can convince yourself that this works by evaluating **NOT TRUE** and **NOT FALSE**. This way of writting **NOT** is also called the **C**-Combinator (or //Cardinal//). </note> </hidden> ==== Natural Numbers ==== Church numerals represent natural numbers as **higher-order functions**. Under this representation, the number //**n**// is a function that maps **f** to its **n-fold composition**. \\ \\ $ N0 = \lambda f.\lambda x. x $ \\ $ N1 = \lambda f.\lambda x. (f \ x) $ \\ $ N2 = \lambda f.\lambda x. (f \ (f \ x)) $ \\ ... <note> Does **N0** look familiar? It's the same as **FALSE** if you rename the variables (using $\alpha$-reduction). </note> You can also define operation on church numerals, some (that were discussed during the lecture) are: \\ \\ $ SUCC = \lambda n.\lambda f.\lambda x.(f \ ((n \ f) \ x)) $ \\ $ ISZERO = \lambda n.((n \lambda x.FALSE) \ TRUE) $ \\ $ ADD = \lambda n.\lambda m.\lambda f.\lambda x.((n \ f) ((m \ f) \ x)) $ \\ \\ **7.1.1** Define multiplication under church numerals: $ MULT = \lambda n.\lambda m. \ ... $ (without using the **Y**-combinator) **7.1.2** Define exponentiation under church numerals: $ EXP = \lambda n.\lambda m. \ ... $ **7.1.3** (*) Define the predecessor operator, that takes a number and returns the number prior to it. What's the predecessor of 0? Evaluate $ PRED \ N0 $. <hidden> $ PRED = \lambda n.\lambda f.\lambda x.(((n \ (\lambda g.\lambda h.h \ (g \ f))) \ (\lambda u.x)) \ (\lambda v.v)) $ \\ \\ $ \phi = \lambda p.PAIR \ (SND \ p) \ (SUCC \ (SND \ p)) $ \\ $ PRED = \lambda.n.FST \ (n \ \phi \ (PAIR \ N0 \ N0)) $ \\ </hidden> \\ **7.1.4** Define substraction under church numerals: $ SUB = \lambda n.\lambda m. \ ... $ (**Hint**: use $ PRED $). What happens if you try to substract a bigger number from a smaller one? Evaluate $ SUB \ N1 \ N2 $. **7.1.5** Define $ LEQ $ (less or equal). $ LEQ n m $ should return **TRUE** if $ n \leq m $ and **FALSE** if $ n > m $. **7.1.6** Define $ EQ $ (equality). $ EQ n m $ should return **TRUE** if $ n = m $ and **FALSE** otherwise. ===== 7.2 Recursion and the Y-Combinator ===== In lambda calculus, recursion is achieved using the fixed-point combinator (or **Y** combinator). \\ A fixed-point combinator is a **higher-order** function that returns some fixed point of it's argument function (**x** is a fixed pointed for a function **f** if $ f(x) = x $). That means: $ f \ (fix \ f) = fix \ f $ \\ And by repeated application: $ fix \ f = f \ (f \ (... f \ (fix \ f)...)) $ \\ Our combinator in lambda calculus looks like this: \\ \\ $ FIX = \lambda f.(\lambda x.f \ (x \ x)) (\lambda x.f \ (x \ x)) $ **7.2.1** Using the **Y**-Combinator, define a function that computes the factorial of a number **n**. **7.2.2** Using the **Y**-Combinator, define a function $ FIB $ that computes the **n**-th fibonacci number. ===== 7.3 Intro to Haskell =====