New work
This commit is contained in:
parent
0151948fb9
commit
923dd2e2a5
|
@ -7,3 +7,306 @@ a.out
|
||||||
.DS_Store
|
.DS_Store
|
||||||
**/.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]
|
-- >>> [1,4,3]
|
||||||
|
|
||||||
doubleEveryOther :: [Int] -> [Int]
|
doubleEveryOther :: [Int] -> [Int]
|
||||||
-- I don't like this code. It doesn't feel very Haskell.
|
-- Base cases.
|
||||||
-- Use list comprehension to get all the indices of xs.
|
doubleEveryOther [] = []
|
||||||
-- Then if the index is odd, double the value.
|
doubleEveryOther [x] = [x]
|
||||||
-- This will double every other starting with the 2nd digit.
|
-- In the recursive case, just multiply the 2nd element from the start.
|
||||||
doubleEveryOther xs = [if myMod i 2 == 0 then xs !! i else myDouble (xs!!i) | i <- [0..(length xs) - 1]]
|
-- Then doubleEveryOther on the rest of the list.
|
||||||
|
doubleEveryOther (x:y:xs) = x : myDouble y : doubleEveryOther xs
|
||||||
|
|
||||||
--mySquare
|
--mySquare
|
||||||
--Write your own my square function using foldr
|
--Write your own my square function using foldr
|
||||||
|
@ -171,9 +172,8 @@ mySquare n = foldr (*) 1 [n,n]
|
||||||
-- 30
|
-- 30
|
||||||
|
|
||||||
sqSum :: [Int] -> Int
|
sqSum :: [Int] -> Int
|
||||||
-- We can use foldr and list comprehension to add evertything in a new
|
-- The lambda function should square and then add to accumulator.
|
||||||
-- list where mySquare was applied (map).
|
sqSum = foldr (\x acc -> mySquare x + acc) 0
|
||||||
sqSum ns = foldr (+) 0 [mySquare x | x <- ns]
|
|
||||||
|
|
||||||
|
|
||||||
--sumDigits is to add the sum of all the number inside the list that is already turn into single digit (10 pts)
|
--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
|
-- >>> 10
|
||||||
|
|
||||||
sumDigits :: [Int] -> Int
|
sumDigits :: [Int] -> Int
|
||||||
-- We can use a double list comprehension combined with foldr.
|
-- The lambda will take the sum of the list of digits of each element
|
||||||
-- Take every n from ns.
|
-- and add it to the accumulator.
|
||||||
-- Find the digits, and then get every digit x.
|
sumDigits = foldr (\x acc -> acc + (sumList $ toDigit x)) 0
|
||||||
-- Combine it all into a list and apply foldr.
|
|
||||||
sumDigits ns = foldr (+) 0 [x | n <- ns, x <- toDigit n]
|
|
||||||
|
|
||||||
-- sepConcat will concatenate the defined seperator to a list of string. If the list is empty despite the defined seperator return empty string.
|
-- 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"
|
-- >>> "a#b#c#d#e"
|
||||||
|
|
||||||
sepConcat :: String -> [String] -> String
|
sepConcat :: String -> [String] -> String
|
||||||
-- Base case 1, when the list is empty.
|
-- The lambda in foldR will prepend the strings+separator to the accumulator but
|
||||||
sepConcat _ [] = []
|
-- skip the separator in the beginning so that the string doesn't end in
|
||||||
-- Pattern match a list with only one element.
|
-- a separator.
|
||||||
-- When we reach this case, we don't add separator to the end.
|
sepConcat sep = foldr (\x acc -> x ++ if acc == [] then acc else sep ++ acc) ""
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
-- Part C: Credit Card problem
|
-- 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.
|
-- If x <= y, the first pair ps should go first.
|
||||||
-- Then we can merge the rest of xs with all of ays.
|
-- Then we can merge the rest of xs with all of ays.
|
||||||
| x <= y = px : mergeList xs 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
|
| otherwise = py : mergeList axs ys
|
||||||
|
|
||||||
|
|
||||||
|
@ -341,8 +335,6 @@ type BigInt = [Int]
|
||||||
clone :: a -> Int -> [a]
|
clone :: a -> Int -> [a]
|
||||||
-- Base case
|
-- Base case
|
||||||
clone _ 0 = []
|
clone _ 0 = []
|
||||||
-- List with just x
|
|
||||||
clone x 1 = x : []
|
|
||||||
-- Create a list with [x], then recursive call function.
|
-- Create a list with [x], then recursive call function.
|
||||||
clone x n = x : clone x (n-1)
|
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
|
removeZero :: BigInt -> BigInt
|
||||||
-- Base case
|
|
||||||
removeZero [] = []
|
|
||||||
-- If we can pattern match a zero, recurse with rest of list.
|
-- If we can pattern match a zero, recurse with rest of list.
|
||||||
removeZero (0:xs) = removeZero xs
|
removeZero (0:xs) = removeZero xs
|
||||||
-- Otherwise just return it.
|
-- Otherwise just return it.
|
||||||
|
@ -399,8 +389,22 @@ removeZero xs = xs
|
||||||
-- bigAdd [9, 9, 9, 9] [9, 9, 9]
|
-- bigAdd [9, 9, 9, 9] [9, 9, 9]
|
||||||
-- >>> [1, 0, 9, 9, 8]
|
-- >>> [1, 0, 9, 9, 8]
|
||||||
|
|
||||||
--bigAdd :: BigInt -> BigInt -> BigInt
|
-- Takes reverse.
|
||||||
bigAdd _ _ = "not implemented"
|
-- 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
|
-- `mulByDigit i n` returns the result of multiplying
|
||||||
|
@ -409,8 +413,20 @@ bigAdd _ _ = "not implemented"
|
||||||
-- mulByDigit 9 [9,9,9,9]
|
-- mulByDigit 9 [9,9,9,9]
|
||||||
-- >>> [8,9,9,9,1]
|
-- >>> [8,9,9,9,1]
|
||||||
|
|
||||||
--mulByDigit :: Int -> BigInt -> BigInt
|
-- Takes reverse.
|
||||||
mulByDigit _ _ = "not implemented"
|
|
||||||
|
-- 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
|
-- `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]
|
-- bigMul [9,9,9,9,9] [9,9,9,9,9]
|
||||||
-- >>> [9,9,9,9,8,0,0,0,0,1]
|
-- >>> [9,9,9,9,8,0,0,0,0,1]
|
||||||
|
|
||||||
--bigMul :: BigInt -> BigInt -> BigInt
|
-- Long multiply algorithm:
|
||||||
bigMul _ _ = "not implemented"
|
-- 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
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -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}
|
|
@ -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 New Issue