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 =
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 =
Printf.printf "%4d: %b\n" x (isLeapYear x);;
Printf.printf "%d: %b\n" x (isLeapYear x);;
(testLeapYear 1400);; (* 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
(*
* 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 =
match day with
1 | 21 | 31 -> (string_of_int day) ^ "st"
| 2 | 22 -> (string_of_int day) ^ "nd"
| 3 | 23 -> (string_of_int day) ^ "rd"
| _ when day > 0 -> (string_of_int day) ^ "th"
| _ -> raise Hell
1 | 21 | 31 -> (string_of_int day) ^ "st"
| 2 | 22 -> (string_of_int day) ^ "nd"
| 3 | 23 -> (string_of_int day) ^ "rd"
| _ when (day > 0 && day < 32) -> (string_of_int day) ^ "th"
| _ -> 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 =
match month with
1 -> "January"
......
let rec digitRoot number =
let result = ref 0 in
let current = ref number in (
Printf.printf "input: %d\n" !current;
(*
* Calculate the digital root of a number: add up all of its digits, and do that
* recursively until a single digit is obtained.
*)
while !current > 0 do
result := !result + (!current mod 10);
Printf.printf "%d + " (!current mod 10);
current := !current / 10;
done;
Printf.printf "= %d\n" !result;
if !result > 9 then
(digitRoot !result)
else
!result
)
let rec digitRoot ?(sum=0) number =
let res = match number with
| _ when number < 10 -> (sum + number)
| _ -> (digitRoot ~sum:(sum + (number mod 10)) (number / 10))
in if res < 10 then res else digitRoot res
;;
let test_digitRoot input =
......@@ -23,8 +15,13 @@ let test_digitRoot input =
Printf.printf "%d -> %d\n" input (digitRoot input)
;;
(test_digitRoot 20);;
(test_digitRoot 24);;
(test_digitRoot 1234);;
(test_digitRoot 123456789);;
(test_digitRoot (-1));; (* what to do with negative numbers? *)
test_digitRoot 20;;
test_digitRoot 24;;
test_digitRoot 1234;; (* = 1 *)
test_digitRoot 65536;; (* = 7 *)
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 =
if (x mod 2) == 0 then
x
else
x - 1
;;
#load "str.cma";;
let isPalindrome palin =
let result = ref true in (
for i = 0 to ((even_len (String.length palin)) / 2) - 1 do
if (palin.[i] != palin.[(even_len (String.length palin)) - i - 1]) then
begin
result := false;
end
else
()
done;
!result)
;;
(*
* The function isPalindrome checks if a given character string is a palindrome,
* i.e. it is identical whether being read from left to right or from right to
* left. Note that this function removes punctuation and word dividers before
* checking the given character string.
*)
let isPalindrome raw =
(*
* Check if the left and right character of the string are the same. An
* empty string and a string with length 1 is by definition a palindrome.
* 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