New work
This commit is contained in:
parent
0151948fb9
commit
923dd2e2a5
5 changed files with 801 additions and 32 deletions
303
.gitignore
vendored
303
.gitignore
vendored
|
@ -7,3 +7,306 @@ a.out
|
|||
.DS_Store
|
||||
**/.DS_Store
|
||||
|
||||
# TeX
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
# *.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
# *.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
||||
|
||||
|
|
|
@ -136,11 +136,12 @@ myDouble n = foldr (+) 0 [n,n]
|
|||
-- >>> [1,4,3]
|
||||
|
||||
doubleEveryOther :: [Int] -> [Int]
|
||||
-- I don't like this code. It doesn't feel very Haskell.
|
||||
-- Use list comprehension to get all the indices of xs.
|
||||
-- Then if the index is odd, double the value.
|
||||
-- This will double every other starting with the 2nd digit.
|
||||
doubleEveryOther xs = [if myMod i 2 == 0 then xs !! i else myDouble (xs!!i) | i <- [0..(length xs) - 1]]
|
||||
-- Base cases.
|
||||
doubleEveryOther [] = []
|
||||
doubleEveryOther [x] = [x]
|
||||
-- In the recursive case, just multiply the 2nd element from the start.
|
||||
-- Then doubleEveryOther on the rest of the list.
|
||||
doubleEveryOther (x:y:xs) = x : myDouble y : doubleEveryOther xs
|
||||
|
||||
--mySquare
|
||||
--Write your own my square function using foldr
|
||||
|
@ -171,9 +172,8 @@ mySquare n = foldr (*) 1 [n,n]
|
|||
-- 30
|
||||
|
||||
sqSum :: [Int] -> Int
|
||||
-- We can use foldr and list comprehension to add evertything in a new
|
||||
-- list where mySquare was applied (map).
|
||||
sqSum ns = foldr (+) 0 [mySquare x | x <- ns]
|
||||
-- The lambda function should square and then add to accumulator.
|
||||
sqSum = foldr (\x acc -> mySquare x + acc) 0
|
||||
|
||||
|
||||
--sumDigits is to add the sum of all the number inside the list that is already turn into single digit (10 pts)
|
||||
|
@ -185,11 +185,9 @@ sqSum ns = foldr (+) 0 [mySquare x | x <- ns]
|
|||
-- >>> 10
|
||||
|
||||
sumDigits :: [Int] -> Int
|
||||
-- We can use a double list comprehension combined with foldr.
|
||||
-- Take every n from ns.
|
||||
-- Find the digits, and then get every digit x.
|
||||
-- Combine it all into a list and apply foldr.
|
||||
sumDigits ns = foldr (+) 0 [x | n <- ns, x <- toDigit n]
|
||||
-- The lambda will take the sum of the list of digits of each element
|
||||
-- and add it to the accumulator.
|
||||
sumDigits = foldr (\x acc -> acc + (sumList $ toDigit x)) 0
|
||||
|
||||
-- sepConcat will concatenate the defined seperator to a list of string. If the list is empty despite the defined seperator return empty string.
|
||||
--
|
||||
|
@ -203,14 +201,10 @@ sumDigits ns = foldr (+) 0 [x | n <- ns, x <- toDigit n]
|
|||
-- >>> "a#b#c#d#e"
|
||||
|
||||
sepConcat :: String -> [String] -> String
|
||||
-- Base case 1, when the list is empty.
|
||||
sepConcat _ [] = []
|
||||
-- Pattern match a list with only one element.
|
||||
-- When we reach this case, we don't add separator to the end.
|
||||
sepConcat _ (t:[]) = t
|
||||
-- On the recursive case, we patten match the first element and the rest
|
||||
-- of the list. We then concat it with the separator and recurse.
|
||||
sepConcat sep (t:ts) = t ++ sep ++ sepConcat sep ts
|
||||
-- The lambda in foldR will prepend the strings+separator to the accumulator but
|
||||
-- skip the separator in the beginning so that the string doesn't end in
|
||||
-- a separator.
|
||||
sepConcat sep = foldr (\x acc -> x ++ if acc == [] then acc else sep ++ acc) ""
|
||||
|
||||
|
||||
-- Part C: Credit Card problem
|
||||
|
@ -290,7 +284,7 @@ mergeList axs@( px@(_,x) : xs) ays@( py@(_,y) : ys)
|
|||
-- If x <= y, the first pair ps should go first.
|
||||
-- Then we can merge the rest of xs with all of ays.
|
||||
| x <= y = px : mergeList xs ays
|
||||
-- Otherwise, we can just call mergeList again.
|
||||
-- Otherwise, we can just call mergeList again and prepend py.
|
||||
| otherwise = py : mergeList axs ys
|
||||
|
||||
|
||||
|
@ -341,8 +335,6 @@ type BigInt = [Int]
|
|||
clone :: a -> Int -> [a]
|
||||
-- Base case
|
||||
clone _ 0 = []
|
||||
-- List with just x
|
||||
clone x 1 = x : []
|
||||
-- Create a list with [x], then recursive call function.
|
||||
clone x n = x : clone x (n-1)
|
||||
|
||||
|
@ -383,8 +375,6 @@ padZero xs ys | xl > yl = (xs, clonez (xl-yl) ++ ys)
|
|||
-- >>> []
|
||||
|
||||
removeZero :: BigInt -> BigInt
|
||||
-- Base case
|
||||
removeZero [] = []
|
||||
-- If we can pattern match a zero, recurse with rest of list.
|
||||
removeZero (0:xs) = removeZero xs
|
||||
-- Otherwise just return it.
|
||||
|
@ -399,8 +389,22 @@ removeZero xs = xs
|
|||
-- bigAdd [9, 9, 9, 9] [9, 9, 9]
|
||||
-- >>> [1, 0, 9, 9, 8]
|
||||
|
||||
--bigAdd :: BigInt -> BigInt -> BigInt
|
||||
bigAdd _ _ = "not implemented"
|
||||
-- Takes reverse.
|
||||
-- Base case, we use n as the carry bit, and so we just leave it at the
|
||||
-- end.
|
||||
bigAdd' [] [] n = [n]
|
||||
-- For recursion, we use mod with the sum to get the digit,
|
||||
-- and then we recurse with the carry bit being the integer division of
|
||||
-- 10.
|
||||
bigAdd' (x:xs) (y:ys) n = (myMod sum 10) : bigAdd' xs ys (div sum 10)
|
||||
where sum = x+y+n
|
||||
|
||||
bigAdd :: BigInt -> BigInt -> BigInt
|
||||
-- We use bigAdd' after we zero-pad the incoming bigInts.
|
||||
-- Since bigAdd' wants reversed, we reverse the lists. We finally have
|
||||
-- to reverse the list at the end again.
|
||||
bigAdd xs ys = removeZero $ reverseList $ bigAdd' (reverseList zxs) (reverseList zys) 0
|
||||
where (zxs,zys) = padZero xs ys
|
||||
|
||||
|
||||
-- `mulByDigit i n` returns the result of multiplying
|
||||
|
@ -409,8 +413,20 @@ bigAdd _ _ = "not implemented"
|
|||
-- mulByDigit 9 [9,9,9,9]
|
||||
-- >>> [8,9,9,9,1]
|
||||
|
||||
--mulByDigit :: Int -> BigInt -> BigInt
|
||||
mulByDigit _ _ = "not implemented"
|
||||
-- Takes reverse.
|
||||
|
||||
-- Base case will just return the carry digits.
|
||||
digMul' [] _ n = reverseList $ toDigit n
|
||||
-- For recursion, we use mod with the sum to get the digit,
|
||||
-- and then we recurse with the carry-over being the integer division of
|
||||
-- 10, where the sum is the digit in the list * q, then added the
|
||||
-- carry-over.
|
||||
digMul' (x:xs) q n = (myMod sum 10) : digMul' xs q (div sum 10)
|
||||
where sum = (x*q)+n
|
||||
|
||||
-- Just delegate to digMul' after reversing the list.
|
||||
mulByDigit :: Int -> BigInt -> BigInt
|
||||
mulByDigit q xs = removeZero $ reverseList $ digMul' (reverseList xs) q 0
|
||||
|
||||
|
||||
-- `bigMul n1 n2` returns the `BigInt` representing the
|
||||
|
@ -422,7 +438,27 @@ mulByDigit _ _ = "not implemented"
|
|||
-- bigMul [9,9,9,9,9] [9,9,9,9,9]
|
||||
-- >>> [9,9,9,9,8,0,0,0,0,1]
|
||||
|
||||
--bigMul :: BigInt -> BigInt -> BigInt
|
||||
bigMul _ _ = "not implemented"
|
||||
-- Long multiply algorithm:
|
||||
-- For each digit in ys, multiply xs by it.
|
||||
-- Based on the index, shift the whole thing by the number of powers of
|
||||
-- 10.
|
||||
-- Then, just bigSum them all.
|
||||
|
||||
-- Helper function.
|
||||
-- Like sumList but for bigInts.
|
||||
-- So megaSum.
|
||||
megaSum :: [BigInt] -> BigInt
|
||||
megaSum [] = [0]
|
||||
megaSum (x:xs) = bigAdd x $ megaSum xs
|
||||
|
||||
bigMul :: BigInt -> BigInt -> BigInt
|
||||
-- Implementation: use megaSum on a list of bigInts.
|
||||
-- We use zip with [0..] and ys to get tuples of the index and the
|
||||
-- value.
|
||||
-- Then, we can use mulByDigit to multiply xs by the digit of y, then
|
||||
-- use the index to add the correct number of zeros to the end.
|
||||
-- Finally the megaSum adds all of the resulting bigInts.
|
||||
bigMul xs ys = megaSum [mulByDigit q xs ++ clone 0 i | (i,q) <- zip [0..] rys]
|
||||
where rys = reverseList ys
|
||||
|
||||
|
||||
|
|
BIN
Assignment2/report2.pdf
Normal file
BIN
Assignment2/report2.pdf
Normal file
Binary file not shown.
421
Assignment2/report2.tex
Normal file
421
Assignment2/report2.tex
Normal file
|
@ -0,0 +1,421 @@
|
|||
%! TeX program = lualatex
|
||||
\RequirePackage[l2tabu,orthodox]{nag}
|
||||
\DocumentMetadata{lang=en-US}
|
||||
\documentclass[a4paper]{scrartcl}
|
||||
\usepackage{geometry}
|
||||
%\usepackage{tikz}
|
||||
%\usepackage{tikz-uml}
|
||||
\usepackage{hyperref}
|
||||
%\usepackage{caption}
|
||||
\usepackage{bookmark}
|
||||
\usepackage{fontspec}
|
||||
\usepackage{microtype}
|
||||
\usepackage{minted}
|
||||
\hypersetup{
|
||||
colorlinks=true,
|
||||
urlcolor=blue
|
||||
}
|
||||
|
||||
% Math packages
|
||||
%\usepackage{amsmath}
|
||||
%\usepackage{mathtools}
|
||||
%\usepackage{amsthm}
|
||||
%\usepackage{thmtools}
|
||||
%\usepackage{lualatex-math}
|
||||
|
||||
% Unicode Math
|
||||
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket},math-style=upright]{unicode-math}
|
||||
\usepackage{newcomputermodern}
|
||||
|
||||
% Use Euler Math fonts and Concrete Roman
|
||||
%\usepackage{euler-math}
|
||||
%\setmainfont{cmunorm.otf}[
|
||||
% BoldFont=cmunobx.otf,
|
||||
% ItalicFont=cmunoti.otf,
|
||||
% BoldItalicFont=cmunobi.otf
|
||||
%]
|
||||
\setmonofont{0xProto}[Scale=MatchLowercase]
|
||||
|
||||
\newcommand*{\figref}[2][]{%
|
||||
\hyperref[{fig:#2}]{%
|
||||
Figure~\ref*{fig:#2}%
|
||||
\ifx\\#1\\%
|
||||
\else
|
||||
\,#1%
|
||||
\fi
|
||||
}%
|
||||
}
|
||||
|
||||
%\DeclarePairedDelimiter\ceil{\lceil}{\rceil}
|
||||
%\DeclarePairedDelimiter\floor{\lfloor}{\rfloor}
|
||||
|
||||
%\declaretheorem[within=chapter]{definition}
|
||||
%\declaretheorem[sibling=definition]{theorem}
|
||||
%\declaretheorem[sibling=definition]{corollary}
|
||||
%\declaretheorem[sibling=definition]{principle}
|
||||
|
||||
\usepackage{polyglossia}
|
||||
%\usepackage[backend=biber]{biblatex}
|
||||
|
||||
\setdefaultlanguage[variant=american,ordinalmonthday=true]{english}
|
||||
|
||||
\day=15
|
||||
\month=3
|
||||
\year=2024
|
||||
|
||||
\title{Programming Assignment 2}
|
||||
\subtitle{CS-420 Spring 2024}
|
||||
\author{Juan Pablo Zendejas}
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
%\listoftheorems[ignoreall,onlynamed={theorem,corollary,principle}]
|
||||
%\listoftheorems[ignoreall,onlynamed={definition},title={List of Definitions}]
|
||||
%\tableofcontents
|
||||
For this programming assignment, I was tasked with creating a variety of
|
||||
functions for different purposes to practice functional programming
|
||||
concepts like fold/reduce, recursion, and function composition. In all,
|
||||
I managed to get a full score on the autograder and I felt that I had
|
||||
created acceptable solutions that are clean and easy to understand.
|
||||
|
||||
While I didn't work with anyone specifically on this project, I did end
|
||||
up searching for help online when I felt I had hit a wall. For example,
|
||||
I wanted to use only one \texttt{foldr} call on my \texttt{sepConcat}
|
||||
function and I was having trouble creating a lambda function that would
|
||||
work. I looked at some
|
||||
StackOverflow\footnote{\url{https://stackoverflow.com/a/44101237}} answers
|
||||
for some guidance and I
|
||||
found I was close, but I just had to re-arrange my use of the \texttt{++}
|
||||
operator to follow the ordering of the \texttt{foldr}. I also found out
|
||||
about the trick of using \texttt{zip [0..] xs} to get the index of each
|
||||
element of a list, which was useful for the final problem.
|
||||
|
||||
Now, we will look at each function and my solution.
|
||||
\section{Part A: Basic Haskell Prelude}
|
||||
These functions are simple implementations using basic Haskell prelude
|
||||
functions.
|
||||
|
||||
\subsection{myMod}
|
||||
The idea is fairly simple. Use \texttt{div} to perform integer division
|
||||
of x and y. Then, we can multiply it by y and subtract that from x to
|
||||
get the remainder of the division, which is the modulus operator.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
myMod :: Int -> Int -> Int
|
||||
myMod x y = x - (y * div x y)
|
||||
\end{minted}
|
||||
|
||||
\subsection{toDigit}
|
||||
This function uses recursion. If the input is \le 0, then we just return
|
||||
an empty list. The recursive step then splits the integer into the first
|
||||
digit using \texttt{myMod}, and then the rest of the number using
|
||||
\texttt{div}. Finally, the digit is appended to the end and toDigit is
|
||||
called recursively to prepend its result.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
toDigit :: Int -> [Int]
|
||||
toDigit n | n <= 0 = []
|
||||
| otherwise = toDigit (div n 10) ++ [myMod n 10]
|
||||
\end{minted}
|
||||
|
||||
\subsection{reverseList}
|
||||
Another recursive function. To reverse the list, I use a pattern
|
||||
matching to split the first element of the list out. Then, just prepend
|
||||
the reverse of the rest of the list to the first element.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
reverseList :: [a] -> [a]
|
||||
reverseList [] = []
|
||||
reverseList (x:xs) = reverseList xs ++ [x]
|
||||
\end{minted}
|
||||
|
||||
\subsection{sumList}
|
||||
Follows a similar strategy. Pattern-matching to split the first element
|
||||
off, then add it to the sum of the rest of the list. This recursive call
|
||||
is ended by a base case of 0 for an empty list.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
sumList :: [Int] -> Int
|
||||
sumList [] = 0
|
||||
sumList (x:xs) = sumList xs + x
|
||||
\end{minted}
|
||||
|
||||
\subsection{toDigitRev}
|
||||
Just a function composition.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
toDigitRev :: Int -> [Int]
|
||||
toDigitRev n = reverseList (toDigit n)
|
||||
\end{minted}
|
||||
|
||||
\section{Part B: Folding Functions}
|
||||
These functions use the \texttt{foldr} prelude function to perform
|
||||
operations on a list.
|
||||
|
||||
\subsection{myDouble}
|
||||
The idea was to use \texttt{foldr} with a list of the parameter twice,
|
||||
so foldr could add them together.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
myDouble :: Int -> Int
|
||||
myDouble n = foldr (+) 0 [n,n]
|
||||
\end{minted}
|
||||
|
||||
\subsection{doubleEveryOther}
|
||||
This function did not have to use \texttt{foldr}. Here, the idea was to
|
||||
use recursion. The recursive case would grab the first two elements and
|
||||
the rest of the list. Then, the 2nd element would be doubled, and the
|
||||
elements would be appended in order but with the doubleEveryOther
|
||||
recursive call for the rest of the list.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
doubleEveryOther :: [Int] -> [Int]
|
||||
doubleEveryOther [] = []
|
||||
doubleEveryOther [x] = [x]
|
||||
doubleEveryOther (x:y:xs) = x : myDouble y : doubleEveryOther xs
|
||||
\end{minted}
|
||||
|
||||
\subsection{mySquare}
|
||||
Similar to myDouble, but using multiply instead of adding them.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
mySquare :: Int -> Int
|
||||
mySquare n = foldr (*) 1 [n,n]
|
||||
\end{minted}
|
||||
|
||||
\subsection{sqSum}
|
||||
Here, we use a custom lambda function. In addition, because the last
|
||||
parameter is the list, we can also use partial function application or
|
||||
currying to omit the name of the first argument and make the declaration
|
||||
cleaner. The lambda function just adds the square of x to the
|
||||
accumulator of \texttt{foldr}.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
sqSum :: [Int] -> Int
|
||||
sqSum = foldr (\x acc -> mySquare x + acc) 0
|
||||
\end{minted}
|
||||
|
||||
\subsection{sumDigits}
|
||||
This function needs to add the digits of all the numbers in the list.
|
||||
Here, the custom lambda function uses the previous \texttt{sumList}
|
||||
and \texttt{toDigit} functions. It adds the sum of the digits of each
|
||||
element to the accumulator.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
sumDigits :: [Int] -> Int
|
||||
sumDigits = foldr (\x acc -> acc + (sumList $ toDigit x)) 0
|
||||
\end{minted}
|
||||
|
||||
\subsection{sepConcat}
|
||||
Concatenate a list of strings while interspersing a separator string in
|
||||
between each string. For this, the custom lambda function will prepend
|
||||
the string to the accumulator, but only put the separator in between if
|
||||
there has already been an element added to the accumulator. This way, we
|
||||
avoid the off-by-one error of appending the separator to the end of the
|
||||
final string.
|
||||
\begin{minted}[frame=single,breaklines=true]{haskell}
|
||||
sepConcat :: String -> [String] -> String
|
||||
sepConcat sep = foldr (\x acc -> x ++ if acc == [] then acc else sep ++ acc) ""
|
||||
\end{minted}
|
||||
|
||||
\section{Part C: Credit Card Problem}
|
||||
This is an application of some of the functions I've written to create a
|
||||
function that validates a credit card number using the Luhn algorithm.
|
||||
Double every other digit of the card number starting from the end
|
||||
(reversed). Take the sum of those digits. If the sum is equal to 0
|
||||
mod 10, it is a valid credit card number.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
validate :: Int -> Bool
|
||||
validate n = myMod (sumDigits (doubleEveryOther (toDigitRev n))) 10 == 0
|
||||
\end{minted}
|
||||
|
||||
\section{Part D: Sorting Algorithms}
|
||||
The task for this section was to implement some sorting algorithms in a
|
||||
functional manner.
|
||||
|
||||
\subsection{splitHalf}
|
||||
For the \texttt{splitHalf} function, it needs to split a list into a tuple where
|
||||
the left and right tuple each have half of the list. To accomplish this,
|
||||
I first created a generic \texttt{mySplit} function that splits onto an
|
||||
index. This is accomplished by taking in an index and a pair of lists.
|
||||
The index is the number of elements from the right pair that should be
|
||||
moved into the left pair. So, every recursive call will move the first
|
||||
element from the right list into the end of the left list. Then, mySplit
|
||||
will be called again with \texttt{n} decremented. The base case, when
|
||||
\texttt{n = 0}, is to just return the pair.
|
||||
|
||||
Finally, \texttt{splitHalf} just calls the \texttt{mySplit} function
|
||||
with \texttt{n} equal to half the length of the list.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
mySplit 0 p = p
|
||||
mySplit n (xs,(y:ys)) = mySplit (n-1) (xs++[y], ys)
|
||||
|
||||
splitHalf :: [a] -> ([a], [a])
|
||||
splitHalf xs = mySplit (div l 2) ([], xs)
|
||||
where l = length xs
|
||||
\end{minted}
|
||||
|
||||
\subsection{mergeList}
|
||||
This is where it starts to get complicated. \texttt{mergeList} is a
|
||||
function that receives two lists of pairs that are sorted by the 2nd
|
||||
element of the pair, and merges them into one big sorted list. The way I
|
||||
thought about this problem after talking with the professor is to
|
||||
consider the first element of each list. Then, I just let the smaller
|
||||
one go first and recurse. To accomplish this, I used a bunch of pattern
|
||||
matching and a guarded statement. Here, \texttt{axs} and \texttt{ays}
|
||||
are the whole lists. Then, \texttt{px} and \texttt{py} are the pairs
|
||||
that I should prepend. \texttt{xs} and \texttt{ys} are the rest of the
|
||||
list without the first element. Finally, \texttt{x} and \texttt{y} are
|
||||
the element the list is sorted by. The guard statement just compares x
|
||||
and y, and uses that information to prepend the pair with the smaller
|
||||
sorting value.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
mergeList :: Ord b => [(a, b)] -> [(a, b)] -> [(a, b)]
|
||||
mergeList [] pys = pys
|
||||
mergeList pxs [] = pxs
|
||||
|
||||
mergeList axs@( px@(_,x) : xs) ays@( py@(_,y) : ys)
|
||||
| x <= y = px : mergeList xs ays
|
||||
| otherwise = py : mergeList axs ys
|
||||
\end{minted}
|
||||
|
||||
\subsection{mergeSort}
|
||||
Finally, I got to implement the merge sort algorithm. I first created
|
||||
some helper functions. \texttt{applyPair} applies a function $f$ with
|
||||
the parameters given by a tuple. \texttt{applyEachPair} applies a
|
||||
function $f$ to both elements of a tuple, and returns a new
|
||||
tuple. Then, \texttt{mergeSort} puts it all together and applies merge
|
||||
sort to each half of the list; then applies mergeList to the pair of the
|
||||
sorted halves. The base cases end the recursion of mergeSort, since a
|
||||
list of 0 or 1 elements is sorted.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
applyPair :: (a->b->c) -> (a,b) -> c
|
||||
applyPair f (x,y) = f x y
|
||||
|
||||
applyEachPair :: (a->b) -> (a,a) -> (b,b)
|
||||
applyEachPair f (x, y) = (f x, f y)
|
||||
|
||||
mergeSort :: Ord b => [(a,b)] -> [(a,b)]
|
||||
mergeSort [] = []
|
||||
mergeSort [x] = [x]
|
||||
mergeSort xs = applyPair mergeList (applyEachPair mergeSort (splitHalf xs))
|
||||
\end{minted}
|
||||
|
||||
\section{Part E: BigInt}
|
||||
Here, I was tasked to work with a new type BigInt which is a list of
|
||||
integers.
|
||||
|
||||
\subsection{clone}
|
||||
Clone takes a value and a number, and creates a list with that value
|
||||
repeated n times. So, a simple recursive solution is to use the cons
|
||||
operator and call clone again with n decremented. The base case is when
|
||||
n = 0, which returns and empty list.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
clone :: a -> Int -> [a]
|
||||
clone _ 0 = []
|
||||
clone x n = x : clone x (n-1)
|
||||
\end{minted}
|
||||
|
||||
\subsection{padZero}
|
||||
This function will take two \texttt{BigInt}s and return a pair of new
|
||||
\texttt{BigInt}s that have the same length. Here, I just made a quick
|
||||
helper function \texttt{clonez} that clones zero n times. Then, I use a
|
||||
guarded expression to prepend zeros based on the difference of the
|
||||
lengths. If \texttt{ys} is shorter, it gets \texttt{xl - yl} zeros
|
||||
prepended, and vice-versa for \texttt{xs}.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
clonez = clone 0
|
||||
|
||||
padZero :: BigInt -> BigInt -> (BigInt, BigInt)
|
||||
padZero xs ys | xl > yl = (xs, clonez (xl-yl) ++ ys)
|
||||
| xl < yl = (clonez (yl-xl) ++ xs, ys)
|
||||
| otherwise = (xs,ys)
|
||||
where xl = length xs
|
||||
yl = length ys
|
||||
\end{minted}
|
||||
|
||||
\subsection{removeZero}
|
||||
Kind of like the opposite of \texttt{padZero}. Takes a \texttt{BigInt}
|
||||
and removes leading zeros that have no value. This is just a simple
|
||||
recursive pattern matching. If the first element is zero, remove it and
|
||||
call \texttt{removeZero} again. If we can't pattern match a zero, just
|
||||
return the list.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
removeZero :: BigInt -> BigInt
|
||||
removeZero (0:xs) = removeZero xs
|
||||
removeZero xs = xs
|
||||
\end{minted}
|
||||
|
||||
\subsection{bigAdd}
|
||||
This function will add two \texttt{BigInt}s. To implement this, I
|
||||
delegated to a helper function \texttt{bigAdd'}. The reasoning was so I
|
||||
could use tail recursion and bring the carry value over each time.
|
||||
|
||||
First, \texttt{bigAdd'} will take two reversed \texttt{BigInt}s, along
|
||||
with a carry bit. We take the sum of the first integers from the lists,
|
||||
along with the carry sum. Then, we take the first digit of the sum and
|
||||
prepend it, and then recursively call \texttt{bigAdd'} with the carry
|
||||
bit being the sum divided by 10, and the rest of the two lists.
|
||||
The base case, then, simply takes empty lists and returns the carry bit.
|
||||
|
||||
The actual implementation of \texttt{bigAdd} pads the incoming
|
||||
\texttt{BigInt}s with zeros, reverses them, and calls \texttt{bigAdd'}
|
||||
with a carry of 0. Finally, at the end, the result is reversed and
|
||||
trimmed of zeros.
|
||||
\begin{minted}[frame=single,breaklines=true]{haskell}
|
||||
bigAdd' [] [] n = [n]
|
||||
bigAdd' (x:xs) (y:ys) n = (myMod sum 10) : bigAdd' xs ys (div sum 10)
|
||||
where sum = x+y+n
|
||||
|
||||
bigAdd :: BigInt -> BigInt -> BigInt
|
||||
bigAdd xs ys = removeZero $ reverseList $ bigAdd' (reverseList zxs) (reverseList zys) 0
|
||||
where (zxs,zys) = padZero xs ys
|
||||
\end{minted}
|
||||
|
||||
\subsection{mulByDigit}
|
||||
I followed a similar strategy to \texttt{bigAdd}. Essentially, the
|
||||
helper function \texttt{digMul'} will take a reversed list, and then
|
||||
multiply the first digit by some factor q. Then, the carry bit is added,
|
||||
and the sum is split into the first digit and the other digits. The
|
||||
first digit is prepended to the recursive call of \texttt{digMul'} with
|
||||
the rest of the list and the same factor.
|
||||
\begin{minted}[frame=single]{haskell}
|
||||
digMul' [] _ n = reverseList $ toDigit n
|
||||
digMul' (x:xs) q n = (myMod sum 10) : digMul' xs q (div sum 10)
|
||||
where sum = (x*q)+n
|
||||
|
||||
mulByDigit :: Int -> BigInt -> BigInt
|
||||
mulByDigit q xs = removeZero $ reverseList $ digMul' (reverseList xs) q 0
|
||||
\end{minted}
|
||||
|
||||
\subsection{bigMul}
|
||||
Finally, the \texttt{bigMul} function will take two \texttt{BigInt}s and
|
||||
multiply them together. This function follows a basic long
|
||||
multiplication algorithm. That is, I take each digit from the second
|
||||
number and multiply it digit-by-digit to the first number. Then, based
|
||||
on its position, I add zeros to the end of the result. To implement this
|
||||
in Haskell, I used a helper function \texttt{megaSum} that recursively
|
||||
adds a list of \texttt{BigInt}s using the previously created
|
||||
\texttt{bigAdd} function. To create the list of numbers to add, I had to
|
||||
reverse the 2nd list \texttt{ys} into \texttt{rys}. Then, by using the
|
||||
\texttt{zip} method, I combined each element of \texttt{rys} with its
|
||||
index. Since the list was reversed, this index is the number of zeros to
|
||||
add onto the sum. Each element of the list passed to \texttt{megaSum} is
|
||||
that digit of \texttt{ys}, \texttt{q}, passed to \texttt{mulByDigit}
|
||||
with the whole \texttt{BigInt} \texttt{xs}. Finally, zeros are appended
|
||||
to the end based on the index. The sum of all of these products is the
|
||||
final result.
|
||||
\begin{minted}[frame=single,breaklines=true]{haskell}
|
||||
megaSum :: [BigInt] -> BigInt
|
||||
megaSum [] = [0]
|
||||
megaSum (x:xs) = bigAdd x $ megaSum xs
|
||||
|
||||
bigMul :: BigInt -> BigInt -> BigInt
|
||||
bigMul xs ys = megaSum [mulByDigit q xs ++ clone 0 i | (i,q) <- zip [0..] rys]
|
||||
where rys = reverseList ys
|
||||
\end{minted}
|
||||
|
||||
\section{Results}
|
||||
The Autograder on EDORAS gave me full marks.
|
||||
|
||||
\begin{Verbatim}[label={Results},frame=single]
|
||||
---------------------------------------------------------------------------
|
||||
Results: [90.00/90.00] | [100.00%]
|
||||
---------------------------------------------------------------------------
|
||||
\end{Verbatim}
|
||||
|
||||
% \inputminted[label={SolutionPA2.hs},breaklines=true]{haskell}{SolutionPA2.hs}
|
||||
|
||||
\end{document}
|
9
Week8/lecture1.hs
Normal file
9
Week8/lecture1.hs
Normal file
|
@ -0,0 +1,9 @@
|
|||
fact :: [Int]
|
||||
fact = scanl (*) 1 [2..]
|
||||
|
||||
fibs :: [Int]
|
||||
-- to understand recursion one must first understand recursion...
|
||||
-- F_n+2 = 1 + sum(F_1 .. F_n)
|
||||
fibs = 1 : scanl (+) 1 fibs
|
||||
|
||||
|
Loading…
Reference in a new issue