Commit e3902d0a authored by Taddeüs Kroes's avatar Taddeüs Kroes

Merge branch 'master' of ssh://vo20.nl/home/git/repos/uva

parents 054c1a97 cc571c55
TEXFLAGS := -halt-on-error -interaction=nonstopmode -file-line-error
all: ass4.pdf
clean:
rm *.out *.toc *.aux *.log *.pdf
%.pdf: %.tex
pdflatex $(TEXFLAGS) $< | grep -i ".*:[0-9]*:.*\|warning" || true
\documentclass[10pt,a4paper]{article}
\usepackage[english]{babel}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,hyperref,graphicx,booktabs,float}
% Paragraph indentation
\setlength{\parindent}{0pt}
\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
\title{Functional programming: week 2, assignment 4}
\author{Sander Mathijs van Veen (6167969; smvv@kompiler.org)}
\begin{document}
\maketitle
\tableofcontents
\newcommand{\s}{\hspace{.3em}}
\newcommand{\la}{\lambda a}
\newcommand{\lb}{\lambda b}
\newcommand{\lp}{\lambda p}
\newcommand{\laq}{\lambda q}
\newcommand{\lu}{\lambda u}
\newcommand{\lv}{\lambda v}
\newcommand{\lx}{\lambda x}
\newcommand{\ly}{\lambda y}
\newcommand{\tb}[1]{\textbf{#1}}
\newcommand{\ra}{\rightarrow_\alpha}
\newcommand{\rb}{\rightarrow_\beta}
\newcommand{\ea}{\equiv_\alpha}
\newcommand{\true}{\la.\lb.a}
\newcommand{\false}{\la.\lb.b}
\newcommand{\truea}{\lu.\lv.u}
\newcommand{\falsea}{\lu.\lv.v}
\section{Negation}
\label{sec:Negation}
Negation inverts the value of a boolean: \texttt{true} becomes \texttt{false},
and \texttt{false} becomes \texttt{true}. In lambda calculi, negation can be
expressed as the $\lambda$-term $\neg x = \lb.\lx.\ly.((b \s y) \s x)$. By
applying $\alpha$-conversions and $\beta$-reductions, we can prove this
$\lambda$-term. First, $\neg \tb{true} \equiv \tb{false}$:
\begin{align*}
\neg \tb{true} & = (\lb.\lx.\ly.((b \s y) \s x) \s \la.\lb.a) \\
& \rb \lx.\ly.((\la.\lb.a \s y) \s x) \\
& \rb \lx.\ly.(\lb.y \s x) \\
& \rb \lx.\ly.y \\
& \ea \tb{false}
\end{align*}
And now $\neg \tb{false} \equiv \tb{true}$:
\begin{align*}
\neg \tb{true} & = (\lb.\lx.\ly.((b \s y) \s x) \s \la.\lb.b) \\
& \rb \lx.\ly.((\la.\lb.b \s y) \s x) \\
& \rb \lx.\ly.(\lb.b \s x) \\
& \rb \lx.\ly.x \\
& \ea \tb{false}
\end{align*}
\pagebreak
\section{Disjunction}
\label{sec:Disjunction}
Disjunction results in \tb{true} whenever one or more of its operands are
\tb{true}. Thus, only iff all operands are \tb{false}, the disjunction will
return \tb{false}.
\begin{align*}
\tb{true} \s\vee\s \tb{true} & = (\lp.(\laq.((p \s p) \s q) \s \true) \s \true) \\
& \rb (\laq.((\true \s \true) \s q) \s \true) \\
& \rb ((\true \s \true) \s \true) \\
& \ra ((\true \s \truea) \s \true) \\
& \rb (\lb.\truea \s \true) \\
& \rb \truea \\
& \ea \tb{true} \\
\end{align*}
\begin{align*}
\tb{true} \s\vee\s \tb{false} & = (\lp.(\laq.((p \s p) \s q) \s \false) \s \true) \\
& \rb (\laq.((\true \s \true) \s q) \s \false) \\
& \rb ((\true \s \true) \s \false) \\
& \ra ((\true \s \truea) \s \false) \\
& \rb (\lb.\truea \s \false) \\
& \rb \truea \\
& \ea \tb{true} \\
\end{align*}
\begin{align*}
\tb{false} \s\vee\s \tb{true} & = (\lp.(\laq.((p \s p) \s q) \s \true) \s \false) \\
& \rb (\laq.((\false \s \false) \s q) \s \true) \\
& \rb ((\false \s \false) \s \true) \\
& \rb (\lb.b \s \true) \\
& \rb \true \\
& \ea \tb{true} \\
\end{align*}
\begin{align*}
\tb{false} \s\vee\s \tb{false} & = (\lp.(\laq.((p \s p) \s q) \s \false) \s \false) \\
& \rb (\laq.((\false \s \false) \s q) \s \false) \\
& \rb ((\false \s \false) \s \false) \\
& \rb (\lb.b \s \false) \\
& \rb \false \\
& \ea \tb{false} \\
\end{align*}
\pagebreak
\section{Conjunction}
\label{sec:Conjunction}
Conjunction results in \tb{true} whenever all of its operands are \tb{true}.
Thus, only iff one or more of operands are \tb{false}, the disjunction will
return \tb{false}.
\begin{align*}
\tb{true} \s\wedge\s \tb{true} & = (\lp.(\laq.((p \s q) \s p) \s \true) \s \true) \\
& \rb (\laq.((\true \s q) \s \true) \s \true) \\
& \rb ((\true \s \true) \s \true) \\
& \ra ((\true \s \truea) \s \true) \\
& \rb (\lb.\truea \s \true) \\
& \rb \truea \\
& \ea \tb{true} \\
\end{align*}
\begin{align*}
\tb{true} \s\wedge\s \tb{false} & = (\lp.(\laq.((p \s q) \s p) \s \false) \s \true) \\
& \rb (\laq.((\true \s q) \s \true) \s \false) \\
& \rb ((\true \s \false) \s \true) \\
& \ra ((\true \s \falsea) \s \true) \\
& \rb (\lb.\falsea \s \true) \\
& \rb \falsea \\
& \ea \tb{false} \\
\end{align*}
\begin{align*}
\tb{false} \s\wedge\s \tb{true} & = (\lp.(\laq.((p \s q) \s p) \s \true) \s \false) \\
& \rb (\laq.((\false \s q) \s \false) \s \true) \\
& \rb ((\false \s \true) \s \false) \\
& \rb (\lb.b \s \false) \\
& \rb \false \\
& \ea \tb{false} \\
\end{align*}
\begin{align*}
\tb{false} \s\wedge\s \tb{false} & = (\lp.(\laq.((p \s q) \s p) \s \false) \s \false) \\
& \rb (\laq.((\false \s q) \s \false) \s \false) \\
& \rb ((\false \s \false) \s \false) \\
& \rb (\lb.b \s \false) \\
& \rb \false \\
& \ea \tb{false} \\
\end{align*}
\end{document}
(*
* Check if the given year is a leap year. This will return true if the given
* integer is larger than 1582, can be divided by 4, but not by 100, or it can
* be divided by 400. Otherwise, false is returned.
*)
let isLeapYear x = let isLeapYear x =
x >= 1582 && x mod 4 == 0 && (x mod 100 != 0 || x mod 400 == 0) x > 1582 && x mod 4 == 0 && (x mod 100 != 0 || x mod 400 == 0)
;; ;;
let testLeapYear x = let testLeapYear x =
Printf.printf "%4d: %b\n" x (isLeapYear x);; Printf.printf "%d: %b\n" x (isLeapYear x);;
(testLeapYear 1400);; (* false *) (testLeapYear 1400);; (* false *)
(testLeapYear 1582);; (* false *) (testLeapYear 1582);; (* false *)
......
(*
* Implementation of date2str.
*
* Given a correct calendar triple (day, month, year), return a proper English
* date. For example: (1, 2, 2011) returns "February 1st, 2011".
*
* The suffix of the day number is not related to the actual month, so "February
* 31st, 2011" can be generated. However, there is no reason to implement error
* checking to prevent returning unvalid day/month combinations (not part of the
* assignment). Note: the assigment clearly states that a correct calendar
* triple is the input of date2str.
*
* This implementation does check for invalid day numbers or invalid month
* numbers. The exception Hell will be raised for these invalid integers.
*)
exception Hell exception Hell
(*
* Given a day number, return the day number followed by its English suffix. For
* example, this will return ``1st'' for day 1, ``23rd'' for day 23 and ``12th'
* for day 12. If the day number is negative or the day number is not between 1
* and 31 (inclusive), Hell will be raised.
*)
let day_with_suffix day = let day_with_suffix day =
match day with match day with
1 | 21 | 31 -> (string_of_int day) ^ "st" 1 | 21 | 31 -> (string_of_int day) ^ "st"
| 2 | 22 -> (string_of_int day) ^ "nd" | 2 | 22 -> (string_of_int day) ^ "nd"
| 3 | 23 -> (string_of_int day) ^ "rd" | 3 | 23 -> (string_of_int day) ^ "rd"
| _ when day > 0 -> (string_of_int day) ^ "th" | _ when (day > 0 && day < 32) -> (string_of_int day) ^ "th"
| _ -> raise Hell | _ -> raise Hell
;; ;;
(*
* Return the English name of a month number (a number between 1 and 12,
* inclusive). If the month number is not defined, Hell will be raised.
*)
let month_name month = let month_name month =
match month with match month with
1 -> "January" 1 -> "January"
......
let rec digitRoot number = (*
let result = ref 0 in * Calculate the digital root of a number: add up all of its digits, and do that
let current = ref number in ( * recursively until a single digit is obtained.
Printf.printf "input: %d\n" !current; *)
while !current > 0 do let rec digitRoot ?(sum=0) number =
result := !result + (!current mod 10); let res = match number with
Printf.printf "%d + " (!current mod 10); | _ when number < 10 -> (sum + number)
current := !current / 10; | _ -> (digitRoot ~sum:(sum + (number mod 10)) (number / 10))
done; in if res < 10 then res else digitRoot res
Printf.printf "= %d\n" !result;
if !result > 9 then
(digitRoot !result)
else
!result
)
;; ;;
let test_digitRoot input = let test_digitRoot input =
...@@ -23,8 +15,13 @@ let test_digitRoot input = ...@@ -23,8 +15,13 @@ let test_digitRoot input =
Printf.printf "%d -> %d\n" input (digitRoot input) Printf.printf "%d -> %d\n" input (digitRoot input)
;; ;;
(test_digitRoot 20);; test_digitRoot 20;;
(test_digitRoot 24);; test_digitRoot 24;;
(test_digitRoot 1234);; test_digitRoot 1234;; (* = 1 *)
(test_digitRoot 123456789);; test_digitRoot 65536;; (* = 7 *)
(test_digitRoot (-1));; (* what to do with negative numbers? *) test_digitRoot 12345678;; (* = 9 *)
test_digitRoot 18273645;; (* = 9 *)
test_digitRoot 123456789;; (* = 9 *)
test_digitRoot 1234567890123456789;; (* = 9 *)
test_digitRoot 999999999998;; (* = 8 *)
test_digitRoot 5674;; (* = 4 *)
let even_len x = #load "str.cma";;
if (x mod 2) == 0 then
x
else
x - 1
;;
let isPalindrome palin = (*
let result = ref true in ( * The function isPalindrome checks if a given character string is a palindrome,
for i = 0 to ((even_len (String.length palin)) / 2) - 1 do * i.e. it is identical whether being read from left to right or from right to
if (palin.[i] != palin.[(even_len (String.length palin)) - i - 1]) then * left. Note that this function removes punctuation and word dividers before
begin * checking the given character string.
result := false; *)
end let isPalindrome raw =
else (*
() * Check if the left and right character of the string are the same. An
done; * empty string and a string with length 1 is by definition a palindrome.
!result) * Check uses a character string `s' and its length `l' to recursively
;; * determine if `s' is a palindrome.
*)
let rec check s l =
l < 2 || (s.[0] == s.[l-1] && (check (String.sub s 1 (l-2)) (l-2)))
in
(* Remove punctuation / word dividers -> only alphanumeric chars remain. *)
let filter = Str.regexp "[^a-zA-Z0-9]+" in
let filtered = String.lowercase (Str.global_replace filter "" raw) in
(check filtered (String.length filtered))
;;
Printf.printf "%b\n" (isPalindrome "asddsa") let test_isPalindrome str =
Printf.printf "isPalindrome(\"%s\") -> %b\n" str (isPalindrome str)
;;
test_isPalindrome "";;
test_isPalindrome "a";;
test_isPalindrome "baas saab";;
test_isPalindrome "never odd or even";;
test_isPalindrome "Was it a rat i saw?";;
test_isPalindrome "expected failure!";;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment