Bachelor thesis (#2)

Write bachelor thesis
master
Ramon Rüttimann 5 years ago committed by GitHub
parent 844dc1de63
commit ca87271792
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

18
.gitignore vendored

@ -0,0 +1,18 @@
.DS_Store
thesis/_minted-thesis
thesis/thesis.aux
thesis/thesis.bbl
thesis/thesis.bcf
thesis/thesis.blg
thesis/thesis.fdb_latexmk
thesis/thesis.fls
thesis/thesis.lof
thesis/thesis.log
thesis/thesis.lot
thesis/thesis.out
thesis/thesis.tex.d
thesis/thesis.toc
thesis/thesis.ist
thesis/code.*
*.swp
*.bak

28
.gitmodules vendored

@ -0,0 +1,28 @@
[submodule "work/common-list-functions/shellcheck"]
path = work/common-list-functions/shellcheck
url = https://github.com/koalaman/shellcheck.git
[submodule "work/common-list-functions/pandoc"]
path = work/common-list-functions/pandoc
url = https://github.com/jgm/pandoc.git
[submodule "work/common-list-functions/postgrest"]
path = work/common-list-functions/postgrest
url = https://github.com/PostgREST/postgrest.git
[submodule "work/common-list-functions/semantic"]
path = work/common-list-functions/semantic
url = https://github.com/github/semantic.git
[submodule "work/common-list-functions/purescript"]
path = work/common-list-functions/purescript
url = https://github.com/purescript/purescript.git
[submodule "work/common-list-functions/compiler"]
path = work/common-list-functions/compiler
url = https://github.com/elm/compiler.git
[submodule "work/common-list-functions/Haxl"]
path = work/common-list-functions/Haxl
url = https://github.com/facebook/Haxl.git
[submodule "work/go"]
path = work/go
url = https://github.com/tommyknows/go.git
branch = bachelor-thesis
[submodule "work/funcheck"]
path = work/funcheck
url = https://github.com/tommyknows/funcheck.git

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,23 @@
# Functional Go
<!--- `Build this document with docker run -it -v (pwd):/build/ pandoc/latex -s /build/README.md -o /build/README.pdf` -->
See `thesis.pdf` for the actual thesis document. That itself links to `thesis/thesis.pdf`.
Structure and Files:
- `thesis`: contains the latex code plus a pre-compiled version of the document.
There are also further tools in that directory that are needed to build the
document.
- `work`: contains subfolders for practical work that was done.
- `common-list-functions`: See the thesis' appendix on what it is.
Contains git submodules and a shell script to acquire the results
that are described in the thesis.
- `examples`: contains different examples of functional Go code. Some code snippets
are described in the thesis, some have been developed out of curiosity.
- `funcheck`: git submodule that contains the implementation of `funcheck' as described
in the thesis.
- `go`: git submodule with the Go compiler code.
- `proposals`: contains old proposals that where submitted.
See Appendix 1 in `thesis.pdf` for more information.

Binary file not shown.

@ -0,0 +1,35 @@
# Functional Go
## Situation
With the rise of Javascript, Rust, and Go, the functional programming paradigm has
gained popularity too. Though none of these programming languages are purely functional,
they all share the common feature of having the possibility to use functional concepts.
However, a lot of programmers struggle initially with the concept of functional
programming. Learning a purely functional programming language is extremely useful
to gain familiarity with these concepts. Purely functional programming languages
like Haskell though are not known for their beginner-friendliness.
What makes learning a functional language difficult is that not only does the
programmer have to learn an entirely different paradigm, but also a syntax that
is uncommon for people coming from imperative or object-oriented languages.
## Objective
The objective is to ease the entry into functional programming by providing a
"harness" for Go that enforces a purely functional style. This harness can either
be a separate stand-alone tool (like `gofmt` or `gopls`) or built into the Go
compiler directly.
The functional Go code could still be valid Go code, but the harness could also apply
simple transformations to the code to make it more performant.
Things to consider while implementing that harness would be immutability (without
introducing unnecessary complications), the possibility to make functional Go code
run and / or compile with regular Go code (code translation?).
Another possibility would be to implement something like "functional-check". What
`shellcheck` is to shell-scripts, `funccheck` is to Go code. It lints existing
Go code and points out the bits that are not functional, displaying rules and
examples. While being conceptually simpler, this would leave most options to the
programmer.
In the end, functional Go should be syntactically familiar to people that have
worked with Go (or C in that regard). With that, one can learn the concepts related
to functional programming, without also needing to learn a new language and syntax.

@ -0,0 +1 @@
thesis/thesis.pdf

@ -0,0 +1,67 @@
LATEXMK ?= latexmk
PDFLATEX ?= pdflatex
PLANTUML ?= plantuml
MAIN_TEX ?= ./thesis.tex
MKARGS = -interaction=nonstopmode -use-make -shell-escape
default: pdf
dvi: $(MAIN_TEX:.tex=.dvi)
pdf: $(MAIN_TEX:.tex=.pdf)
# Rules to compile zhawthesis document class
zhawthesis.cls: zhawthesis.dtx
'$(PDFLATEX)' zhawthesis.dtx
# Rule to compile glossary
thesis.gls:
makeglossaries thesis
skins.sty:
# Dependencies of thesis TeX
-include $(MAIN_TEX).d
# Thesis document creation rules (DVI, PDF)
$(MAIN_TEX:.tex=.dvi): $(MAIN_TEX)
'$(LATEXMK)' -dvi -pdf- -ps- -deps-out='$<.d' $(MKARGS) '$<'
$(MAIN_TEX:.tex=.pdf): $(MAIN_TEX)
'$(LATEXMK)' -pdf -dvi- -ps- -deps-out='$<.d' $(MKARGS) '$<'
# Continuous recompilation when the source files change
watch:
'$(LATEXMK)' -pvc -pdf -dvi- -ps- $(MKARGS) '$(MAIN_TEX)'
# Open the compiled pdf
view: $(MAIN_TEX:.tex=.pdf)
'$(shell command -v xdg-open open | head -n 1)' '$<' >/dev/null 2>&1 &
# Clean up temprary files
clean:
'$(LATEXMK)' -C '$(MAIN_TEX)'
$(RM) zhawthesis.aux zhawthesis.glo zhawthesis.hd zhawthesis.idx zhawthesis.log zhawthesis.out
$(RM) *.synctex.gz *.bbl *.ilg
$(RM) '$(MAIN_TEX).d'
$(RM) *.ist
.PHONY: clean dvi pdf view watch
# Resource compilation rules
%-%.pdf: %.mp
cd '$(dir $(@))' && mpost '$(realpath $(@:.pdf=.mp))'
%.eps: %.plantuml
$(PLANTUML) -teps -v '$<'
%.pdf: %.eps
epstopdf -o='$@' '$<'
%.pdf: %.svg
rsvg-convert -f pdf -o '$@' -d 300 -p 300 '$<'
logos/zhaw/%.pdf: logos/zhaw/%.ai
inkscape --without-gui --export-file='$@' --export-area-drawing --export-margin=1 '$<'

@ -0,0 +1,12 @@
# zhawthesis
Structure follows: https://gpmpublic.zhaw.ch/GPMDocProdDPublic/2_Studium/2_05_Lehre_Studium/T_VL_Vorlage_Berichtstruktur_PA_BA.docx
## Requirements
- A (pdf)LaTeX installation (including the most commonly used packages)
- BibTeX (for bibliography management)
"Optional":
- GNU Make
- `inkscape` (to convert `*.ai` ZHAW logos to PDF)

Binary file not shown.

@ -0,0 +1,42 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
In the last decade, concepts from functional programming have grown in
importance within the wider, non-functional programming community.
Often it is recommended to learn a purely functional programming language
such as Haskell to become familiar with these concepts.
However, many programmers struggle with the double duty
of learning a new paradigm and a new syntax at the same time.
This paper proposes that by learning functional programming with a
multi-paradigm programming language and a familiar syntax it is possible
to lower this effort.
To achieve this goal, the programming language Go has been chosen due to
its syntactical simplicity and familiarity.
However, a downside of Go is the lack of a built-in list type, as lists take a
central role in functional programming. Although this is remediated by Go's slices,
they are not accompanied by any higher-order list processing functions --- `map', `filter', and `fold' to name a
few --- that are present in every functional programming language (and many
other languages too).
Due to the absence of polymorphism, in order to provide these higher-order functions in
a user-friendly way it is necessary to build these functions into the compiler.
Furthermore, this paper adopts a definition of pure functional programming and
introduces `funcheck', a static code analysis tool that is designed to
report constructs that are non-functional.
In conclusion, I demonstrate that with the help of the newly built-in
functions `fmap', `filter', `foldr', `foldl' and
`prepend', as well as `funcheck' to lint code, Go proves itself to be a
suitable language for getting started with functional programming.
The primary factor for this is reflected in the Go idiom `clear is better than clever'.
While functional Go code is more verbose when compared to functional languages, it
is also more obvious about its inner workings.
At the same time, it also illustrates why there is no way around learning a
language such as Haskell if fluency with functional programming concepts
is desired. The main reasons are that, although it may be unusual at first, Haskell's
syntax is extremely concise, and that the language's design --- the type system,
pattern matching, the purity guarantees and more --- provides a very effective toolset
for purely functional programming.

@ -0,0 +1,36 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
Innerhalb der letzten zehn Jahre haben Konzepte und Ideen aus dem funktionalen
Programmieren im Alltag von vielen Entwicklern Fuss gefasst. Häufig wird
empfohlen, eine rein funktionale Programmiersprache wie zum Beispiel Haskell
zu lernen, um sich mit diesen Konzepten vertraut zu machen. Viele haben jedoch
Mühe, eine neue Syntax und ein neues Paradigma gleichzeitig zu lernen. Das Ziel
dieser Arbeit ist deswegen, mit Hilfe einer multiparadigmatischen Programmiersprache mit
bekannter Syntax einen einfacheren Einstieg in funktionales Programmieren zu ermöglichen.
Um dieses Ziel zu erreichen, wurde die Programmiersprache Go aufgrund ihrer
syntaktischen Simplizität und Vertrautheit gewählt.
Da Listen jedoch oft eine zentrale Rolle im funktionalen Programmieren einnehmen, ist ein
Nachteil dieser Wahl, dass Go keinen eingebauten Datentyp für Listen besitzt. Zwar wird
dieser Nachteil durch Go's `Slices' gemildert, jedoch fehlen viele Funktionen höherer
Ordnung um mit Listen zu arbeiten --- `map', `filter' und `reduce', um einige zu nennen.
Da Go's Typensystem keinen Polymorphismus bietet, müssen diese Funktionen im Compiler
implementiert werden, um eine möglichst benutzerfreundliche Verwendung zu ermöglichen.
Zusätzlich dazu wird die Bedeutung von rein funktionalem Programmieren im Kontext dieser Arbeit
festgelegt und auf Basis dieser Definition das Code-Analyse Tool `funcheck' entwickelt, welches
nicht-funktionale Konstrukte im Programmcode meldet.
Mit den neuen eingebauten Funktionen `fmap', `filter', `foldr', `foldl' und `prepend',
sowie dem Linter `funcheck' erweist sich Go als geeignete Programmiersprache um
einen einfachen Einstieg in funktionales Programmieren zu ermöglichen. Der primäre Grund
spiegelt sich auch im Go Idiom `clear is better than clever' wider. Obwohl funktionaler
Go Code länger ist als in funktionalen Sprachen, ist dieser auch einfacher nachzuvollziehen.
Des Weiteren zeigt die Arbeit aber auch, dass es keine Alternative zu einer rein funktionalen
Sprache wie Haskell gibt, um sich funktionales Programmieren vollständig anzueignen.
Haskell's zwar ungewöhnliche, aber prägnante Syntax sowie das Design
der Sprache --- das Typensystem, Pattern Matching, die Reinheitsgarantien und vieles mehr ---
bilden hierfür eine solide und oft verwendete Grundlage.

@ -0,0 +1,35 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
As a part of my bachelor studies, I chose to attend a course on functional programming.
Having worked with Go for the last 3 years, first-class and higher-order functions
were not particularly new ideas to me. However, learning Haskell was, at the beginning,
overwhelming.
I decided to rewrite the exercises that I did not understand in Go.
%So what I did for some exercises that I could not understand completely is that
%I rewrote them in Go.
The result was more verbose; usually
roughly two to three times the lines of code for the same algorithm.
However, after writing the Go version, I understood not only the Go version,
but also the Haskell version.
After doing this several times, I realised that I was constantly rewriting
the same higher-order functions with different types, but more or less the same
implementation. Thus, the idea of adding them as built-ins came up.
`Funcheck' then came into play when I wanted to build something in Go first and
later rewrite it in Haskell. It was hard to tell whether it was purely functional,
but it needed to be in order to be easier to write the implementation in Haskell.
This thesis is written based on my own struggles I had with Haskell, and it is
my hope that someday, someone may benefit from the work done in this thesis.
Special thanks to:
My supervisors Gerrit Burkert and Karl Rege for their support and guidance,
Tom Whiston for proofreading this thesis and improving my English,
Eva Kuske for the consultation on writing and
my employer \href{http://nine.ch}{nine} for their flexible work hours.

@ -0,0 +1,246 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
\section{Learning Functional Programming}
Within the last decade, concepts from functional programming have been brought into the daily life
of almost every programmer. There are many events that contributed to this gain in popularity:
In 2007, C\# 3.0 was released, which introduced lambda expressions and laid the foundations for
turning C\# into a hybrid Object-Oriented / Functional language\autocite{csharp-functional}.
Two years later, Ryan Dhal published the initial version of Node.js, eliminating JavaScript's
ties to the browser and introducing it as a server-side programming language, increasing the
adoption of JavaScript further.
In 2013, Java 8 was released and brought support for lambda expressions and streams.
Within the same time frame, Python has been rapidly growing in popularity\autocite{python-popularity}.
Further, many new multi-paradigm programming languages have been introduced,
including Rust, Kotlin, Go and Dart. They all have functions as first-class citizens in
the language since their initial release.
With these developments, it can be said that functional programming has emerged
from niche use-cases and academia to truly arrive in the wider programming community.
For example Rust, the `most popular programming language' for 5 years in a row (2016--2020)
according to the Stack Overflow Developer survey\autocite{rust-loved}, has been significantly
influenced by functional programming languages\autocite{rust-functional}. Further, in idiomatic
Rust code, a functional style can be clearly observed\footnote{A simple example for this may be
that variables are immutable by default.}.
Learning a purely functional programming language increases fluency with these concepts and
teaches a different way to think and approach problems when programming. Due to this, many
people recommend learning a functional programming
language\autocite{blog1-funcprog}\autocite{blog2-funcprog}\autocite{blog3-funcprog}\autocite{blog4-funcprog},
even if one may not end up using that language at all\autocite{quora-funcprog}.
Most literature about functional programming,
including academia and online resources like blogs, contain code examples written in Haskell.
Further, according to the Tiobe Index\autocite{tiobe-index}, Haskell is also the most popular
purely functional programming language\autocite{comparison-functional-languages}.
\section{Haskell}
Haskell, the \textit{lingua franca} amongst functional programmers, is a lazily-evaluated, purely functional programming
language. While Haskell's strengths stem from all it's features like its advanced type system, pattern matching and more,
these features are also what makes Haskell famously hard to learn\autocite{haskell-hard-one}\autocite{haskell-hard-two}\autocite{haskell-hard-three}\autocite{haskell-hard-four}.
Beginner Haskell programmers face a very distinctive challenge in contrast to learning a new, non-functional programming language:
Not only do they need to learn a new language with an unusual syntax (compared to imperative or object-oriented languages), they
also need to change their way of thinking and reasoning about problems.
For example, the renowned quicksort-implementation from the Haskell Introduction Page\autocite{haskell-quicksort}:
\begin{listing}
\begin{haskellcode}
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
\end{haskellcode}
\caption{Quicksort implementation in Haskell}\label{code:haskell-quicksort}
\end{listing}
While this is only a very short and clean piece of code, these 6 lines already pose many challenges to non-experienced Haskellers:
\begin{itemize}
\item The function's signature with no `fn' or `func' statement as they often appear in imperative languages
\item The pattern matching, which would be a `switch' statement or a chain of `if / else' conditions
\item The deconstruction of the list within the pattern matching
\item The functional nature of the program, passing `(< p)' (a function returning a function) to another function
\item The function call to `filter' without parenthesised arguments and no clear indicator at which arguments
it takes and which types are returned
\end{itemize}
Although some of these constructs also exist in imperative or object-oriented languages, the cumulative difference
is not to underestimate and adds to Haskell's steep learning curve.
\section{Goals}
As demonstrated in the example above, learning a new paradigm and syntax at the same time
can be daunting and discouraging for novices.
The entry barrier for functional programming should be lowered by
using a modern, multi-paradigm language with a clear and familiar syntax. The functional
programming beginner should be able to focus on the paradigm first, and then change to a language
like Haskell to fully get into functional programming.
To achieve this goal, this thesis will consist of two parts.
In the first part, writing functional code will be made as easy as possible. This means that
a programming language with an easy and familiar syntax should be chosen. Optimally, this language
should already support functions as first-class citizens. Additionally, it should be statically
typed, as a static type system makes it easier to reason about a program and can support the
programmer while writing code.
In the second part, a linter will be created to check code for non-functional statements. To achieve
this, a definition of what functional purity means has to be selected and a ruleset has to be
worked out and implemented into a static analysis tool.
\section{Why Go}\label{sec:why-go}
The language of choice for this task is Go, a statically typed, garbage-collected programming language
designed at Google in 2009\autocite{golang-publish}. With its strong syntactic similarity to C, it should
be familiar to most programmers.
Go strives for simplicity and its syntax is extremely small and easy to learn. For example, the
language consists of only 25 keywords and purposefully omits constructs like the ternary operator
(<bool> ? <then> : <else>) as a replacement for the longer `if <bool> \{ <then> \} else \{ <else> \}'
for clarity. `A language needs only one conditional control flow construct'\autocite{go-ternary},
and this also holds true for many other constructs. In Go, there is usually only one way
to express something, improving the clarity of code.
Due to this clarity and unambiguity, the language is a perfect fit to grasp the concepts and trace
the inner workings of functional programming. It should be easy to read code and understand what
it does without a lot of experience with the language.
There are however a few downsides of using Go. Currently, Go does not have polymorphism, which means
that functions always have to be written with specific types. Due to this, Go also does not include
common list processing functions like `map', `filter', `reduce' and more\footnote{Although Go does
have some polymorphic functions like `append', these are specified as built-in functions in the
language and not user-defined}. Further, Go does not have a built-in `list' datatype. However, Go's
`slices' cover a lot of use cases for lists already. Section~\ref{sec:go-slices} covers this topic
in more detail.
\section{Existing Work}
With Go's support of some functional aspects, patterns and best practices have emerged that make
us of functional programming constructs.
For example, in the \textit{net/http} package of the standard library, the function
\begin{gocode}
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
\end{gocode}
is used to register functions for http server handling\autocite{go-http-doc}:
\begin{code}
\begin{gocode}
func myHandler(w http.ResponseWriter, r *http.Request) {
// Handle the given HTTP request
}
func main() {
// register myHandler in the default ServeMux
http.HandleFunc("/", myHandler)
http.ListenAndServe(":8080", nil)
}
\end{gocode}
\caption{Go web server handler function}
\end{code}
Using functions as function parameters or return types is a commonly used feature in Go, not just
within the standard library. Furthermore, design patterns have emerged within the community
that use functional concepts. An example of this are `functional options'.
\subsection{Functional Options}
The `functional options' pattern has been outlined in Dave Cheney's blog post `Functional options
for friendly APIs'\autocite{functional-options} and is a great example on how to use the support for multiple paradigms.
The basic idea with functional options is that a type constructor receives an unknown (0-n) amount
of options:
\begin{code}
\begin{gocode}
func New(requiredSetting string, opts ...option) *MyType {
t := &MyType{
setting: requiredSetting,
featureX: false,
}
for _, opt := range opts {
opt(t)
}
return t
}
type option func(t *MyType)
\end{gocode}
\caption{Constructor with functional options}
\end{code}
These options can then access the instance of \mintinline{go}|MyType| to modify it accordingly,
for example:
\begin{code}
\begin{gocode}
func EnableFeatureX() option {
return func(t *MyType) {
t.featureX = true
}
}
\end{gocode}
\caption{Example for a functional option}
\end{code}
To enable feature X, `New' can be called with that option:
\begin{gocode}
t := New("required", EnableFeatureX())
\end{gocode}
With this pattern, it is easy to introduce new options without breaking old usages of the API.
Furthermore, the typical `config struct' pattern can be avoided and meaningful zero values
can be set.
A more extensive example on how functional options are implemented and used can be found in
Appendix~\ref{appendix:funcopts}.
\begin{quote}
In summary
\begin{itemize}
\item Functional options let you write APIs that can grow over time.
\item They enable the default use case to be the simplest.
\item They provide meaningful configuration parameters.
\item Finally they give you access to the entire power of the language to initialize complex values.
\end{itemize}\autocite{functional-options}
\end{quote}
While this is a great example of what can be done with support for functional concepts, a purely functional approach to
Go has so far been discouraged by the core Go team, which is understandable for a multi-paradigm programming language.
However, multiple developers have already researched and tested Go's ability to do functional programming.
\subsection{Functional Go?}
In his talk `Functional Go'\autocite{func-go-talk}, Francesc Campoy Flores analysed some commonly used functional
language features in Haskell and how they can be copied to Go. Ignoring speed and stack overflows due to non-existent
tail call optimisation\autocite{go-tco}, the main issue is with the type system and the missing polymorphism.
\subsection{go-functional}
In July 2017, Aaron Schlesinger, a Go programmer for Microsoft Azure, gave a talk on functional programming with Go.
He released a repository\autocite{go-functional} that contains `core utilities for functional Programming in Go'.
The project is currently unmaintained, but showcases functional programming concepts like currying, functors and
monoids in Go. In the `README' file of the repository, he also states that:
\begin{quote}
Note that the types herein are hard-coded for specific types, but you could
use code generation to produce these FP constructs for any type you please!
\autocite{go-functional-readme}
\end{quote}
\section{Verdict}
The aforementioned projects showcase the main issue with functional programming in Go: the missing
helper functions that are prevalent in functional languages and that they currently cannot be implemented
in a generic way.
To make functional programming more accessible in Go, this thesis will research what the most used
higher-order functions are and implement them with a focus on usability.
Furthermore, to learn purely functional programming, a list of rules for pure functional code should
be curated and implemented in a static code analysis tool. This tool can then be used to check
existing code and report constructs that are not functional.

@ -0,0 +1,273 @@
This chapter introduces the core concepts in Go that are needed to follow this paper.
Go is a language similar to C, although with a few minor, but important differences.
First, Go is garbage collected, meaning that the programmer does not need to allocate
and free memory\footnote{although allocating memory is possible with the \mintinline{go}|new|
built-in function}. Secondly, Go does not allow for pointer arithmetic.
`Without pointer arithmetic it's possible to create a language that can never derive an
illegal address that succeeds incorrectly'\autocite{go-pointerarithmetic}.
Further, Go provides a built-in data type that does not exist in plain C: slices.
\section{Go Slices}\label{sec:go-slices}
As mentioned in Section~\ref{sec:why-go}, Go does not have a `list' implementation and lists are rarely used.
The reason for this
is twofold. Firstly, as Go does not have polymorphism, it is not possible for users to implement a generic
`list' type that would work with any underlying type. Secondly, the Go authors added `slices' as a core type
to the language. From a usage perspective, lists would not add anything compared to slices.
Go's Slices can be viewed as an abstraction over arrays, to mitigate some of the weaknesses of arrays
when compared to lists.
\begin{quote}
Arrays have their place, but they're a bit inflexible, so you don't see them too often in Go code.
Slices, though, are everywhere. They build on arrays to provide great power and convenience.\autocite{golang-slices}
\end{quote}
Slices can be visualised as a `struct' over an array:
\begin{gocode}
// NOTE: this type does not really exist, it
// is just to visualise how they are implemented.
type Slice struct {
// the underlying "backing store" array
array *[]T
// the length of the slice / view on the array
len int
// the capacity of the array from the
// starting index of the slice
cap int
}
\end{gocode}
With the `append' function, elements can be added to a slice. Should the underlying array not have enough
capacity left to store the new elements, a new array will be created and the data from the old array will
be copied into the new one. This happens transparently to the user.
\subsection{Using Slices}
`head', `tail' and `last' operations can be done with index expressions:
\begin{gocode}
// []<T> initialises a slice, while [n]<T> initialises an
// array, which is of fixed length n. We're only working
// with slices here.
s := []string{"first", "second", "third"}
head := s[0]
tail := s[1:]
last := s[len(s)-1]
\end{gocode}
Adding elements or joining slices is achieved with `append':
\begin{gocode}
s := []string{"first", "second"}
s = append(s, "third", "fourth")
t := []string{"fifth", "seventh"}
s = append(s, t...)
// to prepend an element, one has to create a
// slice out of that element
s = append([]string{"zeroth"}, s...)
\end{gocode}
Append is a variadic function, meaning it takes \textit{n} elements. If the slice is of type \mintinline{go}|[]T|,
the appended elements have to be of type \mintinline{go}|T|.
To join two lists, the second list is expanded into
variadic arguments.
More complex operations like removing elements, inserting elements in the middle or finding
elements in a slice require helper functions, which have also been documented in Go's
Slice Tricks\autocite{slice-tricks}.
\subsection{What is missing from Slices}
This quick glance at slices should clarify that, though the runtime characteristics of lists and slices
can differ, from a usage standpoint, what is possible with lists is also possible with slices.
In a typical program written in a functional language, lists take a central role\footnote{Interestingly,
there is no clear and direct answer as to why they do. One reason may be because they are recursively
defined and trivially to implement functionally. Further, they are easier to use than arrays, where
the programmer would need to track the index and bound of the array (imagine keeping track of the
indices in a recursive function)\autocite{why-lists}}. Because of this, functional languages have
a number of helper functions like `map', `filter' and `fold'\autocite{haskell-list-funcs} to modify and
work on lists. These so called `higher order functions' currently do
not exist in Go and would need to be implemented by the programmer. With no support for polymorphism, a
different implementation would need to be written for every slice-type that is used. The type \mintinline{go}|[]int|
(read: a slice of integers) differs from \mintinline{go}|[]string|, which means that a possible
`map' function would have to be written once to support slices of integers, once to support slices
of strings, and a combination of these two:
\begin{gocode}
func mapIntToInt(f func(int) int, []int) []int
func mapIntToString(f func(int) string, []int) []string
func mapStringToInt(f func(string) int, []string) []int
func mapStringToString(f func(string) string, []string) []string
\end{gocode}
With 7 base types (eliding the different `int' types like `int8', `uint16`, `int16', etc.), this would
mean $7^{2} = 49$ map functions just to cover the base types. Counting the different numeric
types into that equation (totally 19 distinct types\autocite{go-basetypes}), would grow that number to $19^{2} = 361$ functions.
Though this code could be generated, it misses user-defined types which would still
need to be generated separately in a pre-compile step.
Another option, instead of having a function per type, would be that `map' takes and returns empty interfaces
(\mintinline{go}|interface{}|). However, `the empty interface says
nothing'\autocite{empty-interface}. The declaration of `map' would be:
\begin{gocode}
func map(f func(interface{}) interface{}, interface{}) interface{}
\end{gocode}
This function header does not say anything about it's types, which would
mean that they would need to be checked at runtime and handled gracefully. It
would also require the caller to do a type assertion after every call. Further,
a slice of type \mintinline{go}|T| cannot simply be converted or asserted to a slice of another type
\mintinline{go}|T2|\autocite{go-interface-slice-conv}\autocite{go-interface-slice-conv2}.
Because of this limitation, a typical usage pattern of map would be:
\begin{gocode}
s := []string{"hello", "world"}
var i []interface{}
for _, e := range s {
i = append(i, e)
}
// i is now populated and can be used.
r := map(someFunc, f)
// to convert it back to []string:
s = r.([]string)
\end{gocode}
This exemplifies why using the empty interface is not an option. Further, the
function could not really be type-checked at compile time, as there is no indication
of which argument's type must be equal.
\section{Built-in functions}
To mitigate these issues, the most common list-operations (in Go slice-operations) will
be added as built-ins to the compiler, so that the programmer can use these functions
on every slice-type without any conversion or code generation being necessary.
The language specification defines what built-in functions are and which built-in
functions should exist:
\begin{quote}
Built-in functions are predeclared. They are called like any other function
but some of them accept a type instead of an expression as the first argument.
The built-in functions do not have standard Go types, so they can only appear
in call expressions; they cannot be used as function values.\autocite{go-spec-builtins}
\end{quote}
For example, the documentation for the built-in \mintinline{go}|append|:
\begin{gocode}
// The append built-in function appends elements to the end of a slice.
// ...
func append(slice []Type, elems ...Type) []Type
\end{gocode}
The documentation shows that the types supplied to append are not specified upfront.
Instead, they are resolved and checked during compilation of the program.
Thus, in order to have generic list processing functions, these functions need to
be implemented as built-ins in the compiler.
\section{The Go Compiler}
The Go programming language is defined by its specification\autocite{go-spec}, and not
it's implementation. As of Go 1.14, there are two major implementations of that
specification; Google's self-hosting compiler toolchain `gc', which is written in
Go, and `gccgo', a front end for GCC, written in C++.
When talking about the Go compiler, what's mostly referred to is `gc'\footnote{`gc' stands
for `go compiler', and not `garbage collection' (which is abbreviated as `GC').}.
A famous, although not completely correct story tells about Go being designed
while a C++ program was compiling\autocite{less-is-more}.
This is why one of the main goals when designing Go was fast compilation times:
\begin{quote}
Finally, working with Go is intended to be fast: it should take at most a few
seconds to build a large executable on a single computer. To meet these goals
required addressing a number of linguistic issues: an expressive but lightweight
type system; concurrency and garbage collection; rigid dependency specification;
and so on. These cannot be addressed well by libraries or tools; a new language
was called for.\autocite{go-faq}
\end{quote}
Go has taken some measures to combat slow compilation times. In general, Go's dependency resolution is simpler
compared to other languages, for example by not allowing circular dependencies.
Furthermore, compilation is not even attempted if there are unused
imports or unused declarations of variables, types and functions.
This leads to less code to compile and in turn shorter compilation times.
Another reason is that `the `gc' compiler is simpler code compared to most
recent compilers'\autocite{nuts-compiler}. However, according
to Rob Pike, one of the creators of Go, Go's compiler is not notably fast, but
most other compilers are slow:
\begin{quote}
The compiler hasn't even been properly tuned for speed. A truly fast compiler
would generate the same quality code much faster.\autocite{nuts-compiler}
\end{quote}
The code generation with the `gc' compiler is split into four phases:
\subsection{Parsing Go programs}
\newglossaryentry{dag}{name=DAG, description={Directed Acyclic Graph}}
\newglossaryentry{ast}{name=AST,description={Abstract Syntax Tree, an abstract representation of source code as a tree}}
The first phase of compilation is parsing Go programs into a syntax tree. This
is done by tokenising the code (`lexical analysis' - the `lexer'), parsing
(`syntax analysis' - the `parser') it and then constructing a syntax tree
(\gls{ast})\footnote{Technically, the syntax tree is a syntax \gls{dag}\autocite{ast-node-dag}}
for each source file.
Go has been designed to be easy to parse and analyse. For example, in contrast
to many other programming languages,
Go does not require a symbol table to parse source code.\autocite{go-faq-symbol}.
\subsection{Type-checking and AST-transformation}\label{sec:comp-type}
The second phase of compilation starts by converting the `syntax' package's
AST, created in the first phase, to the compiler's AST representation. This
is due to historical reasons, as gc's AST definition was carried over
from the C implementation.
After the conversion, the AST is type-checked. Within the type-checking, there
are also some additional steps included like checking for `declared and not used'
variables and determining whether a function terminates.
After type-checking, transformations are applied on the AST. This includes
eliminating dead code, inlining function calls and escape analysis, to name a few.
What is also done in the transformation phase is rewriting built-in function
calls, replacing for example a call to the built-in `append' with the necessary
AST structure and runtime-calls to implement its functionality.
\subsection{SSA}
\newglossaryentry{ssa}{name=SSA,description={Single Static Assignment, an intermediate representation between the AST and the compiled binary that simplifies and improves compiler optimisations}}
In the third phase, the AST is converted to \gls{ssa} form. SSA (Single Static Assignment) is `a
lower-level intermediate representation with specific properties that make it
easier to implement optimizations and to eventually generate machine code from
it'\autocite{compiler-readme}.
The conversion consists of multiple `passes' through the SSA that
apply machine-independent rules to optimise code. These generic
rewrite rules are applied on every architecture and thus mostly
concern expressions (for example replacing expressions with constant values and
optimising multiplications), dead code elimination and removal of unneeded
nil-checks.
\subsection{Generating machine code}
Lastly, in the fourth phase of the compilation, machine-specific
SSA optimisations are applied. These may include:
\begin{itemize}
\item Rewriting generic values into their machine-specific variants
(for example, on amd64, combining load-store operations)
\item Dead-code elimination
\item Pointer liveness analysis
\item Removing unused local variables
\end{itemize}
After generating and optimising the SSA form, the code is passed to the
assembler, which replaces the so far generic instructions with
architecture-specific machine code and writes out the final object file\autocite{compiler-readme}.

@ -0,0 +1,8 @@
\section{Slice Helper Functions}
\input{chapters/31_builtins.tex}
\section{Functional Check}\label{sec:funcheck-theory}
\input{chapters/32_funcheck.tex}

@ -0,0 +1,319 @@
\subsection{Choosing the functions}
As mentioned in the introduction, the goal is to make functional programming in Go easier.
To achieve this, the first task is to implement some helper functions for slices, similar to those that exist
for lists in Haskell. To decide on which functions will be implemented, popular
Haskell repositories on GitHub have been analysed. The popularity of repositories
was decided to be based on their number of stars. Out of all Haskell projects
on GitHub, the most popular are\autocite{github-popular-haskell}:
\begin{itemize}
\item Shellcheck (koalaman/shellcheck\autocite{github-shellcheck}): A static analysis tool for shell scripts
\item Pandoc (jgm/pandoc\autocite{github-pandoc}): A universal markup converter
\item Postgrest (PostgREST/postgrest\autocite{github-postgrest}): REST API for any Postgres database
\item Semantic (github/semantic\autocite{github-semantic}): Parsing, analyzing, and comparing source code across many languages
\item Purescript (purescript/purescript\autocite{github-purescript}): A strongly-typed language that compiles to JavaScript
\item Compiler (elm/compiler\autocite{github-elmcompiler}): Compiler for Elm, a functional language for reliable web apps
\item Haxl (facebook/haxl\autocite{github-haxl}): A Haskell library that simplifies access to remote data, such as databases or web-based services
\end{itemize}
In these repositories, the number of occurrences of popular list functions has
been counted. The analysis does not differentiate between different `kinds' of
functions. For example, `fold' includes all occurrences of \mintinline{haskell}|foldr|,
\mintinline{haskell}|foldl| and \mintinline{haskell}|foldl'|; `map' also includes
occurrences of \mintinline{haskell}|fmap|.
Further, the analysis has not been done with any kind of AST-parsing.
Rather, a simple `grep' has been used to find matches. This means that it is
likely to contain some mismatches, for example in code comments. All in all,
this analysis should only be an indicator of what functions are used most.
Running the analysis on the 7 repositories listed above, searching for a number
of pre-selected list functions, indicates that the most used functions are `:'
(cons), `map' and `fold', as shown in table~\ref{tab:occurrences-list-funcs}.
\begin{table}[htb]
\centering
\begin{tabular}{ll}
\toprule
`:' (cons) & 2912 \\
\midrule
map, fmap & 1873 \\
\midrule
foldr, foldl, foldl' & 303 \\
\midrule
filter & 262 \\
\midrule
reverse & 154 \\
\midrule
take & 108 \\
\midrule
drop & 81 \\
\midrule
maximum & 45 \\
\midrule
sum & 44 \\
\midrule
zip & 38 \\
\midrule
product & 15 \\
\midrule
minimum & 10 \\
\end{tabular}
\caption[Occurrences of list functions]{Occurrences of list functions\footnotemark}
\label{tab:occurrences-list-funcs}
\end{table}
\footnotetext{See Appendix~\ref{appendix:function-occurrences} for how these results have been achieved}
Based on this information, it has been decided to implement the map, cons, fold
and filter functions into the Go compiler.
\subsection{Map}
The most used function in Haskell is map. The table~\ref{tab:occurrences-list-funcs}
counts roughly 1250 occurrences of map, although around 600 of those are from `fmap'.
fmap is part of the Functor type class\footnote{type classes
in Haskell are similar to interfaces in imperative and object-oriented
languages}, which is described as `a type that can be mapped over'\autocite{functor-wiki}.
In general, a common analogy of the Functor type class is a box. A functor is like a box
where a value can be put into and taken out again. fmap processes and transforms the item
in that box. For lists, this process means iterating over and processing every item within that list.
For the `Maybe' type it means `unpacking' the concrete value and processing it, or if there is
no concrete value, returning `Nothing' instead.
The map function is exactly like fmap but only works on lists:
\begin{quote}
\[map\] returns a list constructed by applying a function (the first argument) to all
items in a list passed as the second argument\autocite{haskell-map}.
\end{quote}
Some usage examples of map can be seen at~\ref{code:haskell-map}.
\begin{listing}
\begin{haskellcode}
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> map (*3) [1,2,3]
[3,6,9]
Prelude> fmap (*3) [1,2,3]
[3,6,9]
Prelude> map (++ " world") ["hello","goodbye"]
["hello world","goodbye world"]
Prelude> map show [1,2,3]
["1","2","3"]
\end{haskellcode}
\caption{Example usage for map and fmap}\label{code:haskell-map}
\end{listing}
Due to missing polymorphism, map cannot be implemented easily in Go. While
a specific definition of map would be
\begin{gocode}
func map(f func(int) string, []int) []string
\end{gocode}
this definition would only hold true for the specific type combination \mintinline{go}|int|
and \mintinline{go}|string|. A more generic definition, similar to append,
would be:
\begin{gocode}
func map(f func(Type1) Type2, []Type1) []Type2
\end{gocode}
For this to work, the function has to be implemented as a built-in into the compiler.
As there is already a `map' token in the Go compiler (for the map data type),
the function will be called `fmap'. However, compared to Haskell's `fmap',
Go's `fmap' only works on slices. This is due
to the absence of an `functor'-like concept. Again, due to the absence of polymorphism,
this cannot realistically built into the language in this context.
Nonetheless, to avoid possible naming confusions, the `map' function in Go will
be called `fmap'.
In Go, the usage of `fmap' should result in making the program~\ref{code:fmap-usage-go}
behave as shown\footnote{Printf's first argument, the
verb `\%\#v', can be used to print the type (`\#') and the value (`v') of a
variable\autocite{fmt-godoc}.}.
\begin{listing}
\begin{gocode}
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Printf("%#v", fmap(strconv.Itoa, []int{1, 2, 3})) // []string{"1", "2", "3"}
}
\end{gocode}
\caption{Example usage of map in Go}\label{code:fmap-usage-go}
\end{listing}
\subsection{Cons}
The name cons has been introduced by LISP, where it describes a record structure
containing two components called the `car' (the `\textbf{c}ontents of the \textbf{a}ddress \textbf{r}egister')
and the `cdr' (`\textbf{c}ontent of \textbf{d}ecrement \textbf{r}egister').
Lists are built upon cons cells, where the `car' stores the element and `cdr' a
pointer to the next cell - the next element of the list.
This is why in Lisp, \mintinline{lisp}|(cons 1 (cons 2 (cons 3 (cons 4 nil))))| is equal to
\mintinline{lisp}|(list 1 2 3 4)|. This list is also visualised in picture~\ref{fig:cons}.
\begin{figure}[h!]
\includegraphics[width=\linewidth]{../img/cons.png}
\caption{Cons cells forming a list\autocite{cons-image-source}}
\label{fig:cons}
\end{figure}
The cons operator thus prepends an element to a list, effectively allocating a
variable that contains the newly added element and a pointer to the `old' list.
As a result, prepending to a list is computationally cheap, needing one allocation
and one update.
In Haskell, the `name' of the cons function is the `:' operator.
In Go, names for identifiers (which includes function names) underlie a simple
rule:
\begin{quote}
An identifier is a sequence of one or more letters and digits. The first
character in an identifier must be a letter.\autocite{spec-identifiers}
\end{quote}
This rule forbids a function to be named `:'. Instead, the function could be
named `cons'. However, Go already has a function to add to the end of a slice,
`append'. Thus, adding to the beginning of a slice will be named `prepend'.
Using prepend should be very similar to append. The behaviour of `prepend'
should be equal to using `append' with a slight workaround\footnote{This workaround
is to create a slice containing the prepended element, and expanding the
destination slice with `...', as \mintinline{go}|append| is a variadic function}:
\begin{listing}
\begin{gocode}
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Printf("%#v", append([]int{0}, []int{1,2,3}...)// []int{0, 1, 2, 3}
fmt.Printf("%#v", prepend(0, []int{1, 2, 3})) // []int{0, 1, 2, 3}
}
\end{gocode}
\caption{Example usage of prepend in go}\label{code:prepend-go}
\end{listing}
\subsection{Fold}\label{sec:fold}
Fold, sometimes also named `reduce' or `aggregate', is another higher-order function
that is very commonly used in functional programming.
\begin{quote}
fold refers to a family of higher-order functions that
analyze a recursive data structure and through use of a given
combining operation, recombine the results of recursively processing its
constituent parts, building up a return value.\autocite{fold-wiki}
\end{quote}
In other words, fold processes a list one by one and executes a `combining operation'
on every element, for example summing up a list of integers.
The family of fold functions in Haskell consist of three different implementations of
that definition: foldr, foldl and foldl'.
The difference between foldr and foldl is hinted at their function headers:
\begin{listing}
\begin{haskellcode}
Prelude Data.List> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Prelude Data.List> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
\end{haskellcode}
\caption{Function headers of the fold functions}
\end{listing}
The argument with type `b' is passed as the first argument to the foldl
function, and as the second argument to foldr. As can be seen in the illustrations
of foldl and foldr in~\ref{fig:fold}, the evaluation order of the two functions
differ.
\begin{figure}[h!]
\centering
\includegraphics[scale=0.5]{../img/foldl.png}
\includegraphics[scale=0.5]{../img/foldr.png}
\caption{Folds illustrated\autocite{fold-wiki}}
\label{fig:fold}
\end{figure}
This is most obvious when using an example where the function is not associative:
\begin{listing}
\begin{haskellcode}
foldl (-) 0 [1..7]
((((((0 - 1) - 2) - 3) - 4) - 5) - 6) - 7 = -28
foldr (-) 0 [1..7]
1 - (2 - (3 - (4 - (5 - (6 - (7 - 0)))))) = 4
\end{haskellcode}
\caption{foldr and foldl execution order}\label{code:foldr-example}
\end{listing}
In foldl, the accumulator (`0') is added to the left end of the list (prepended),
while with foldr, the accumulator is added to the right end.
For associative functions (e.g. `+') this does not make a difference, it does
however for non-associative functions, as can be seen in the example~\ref{code:foldr-example}.
The difference between foldl and foldl' is more subtle:
\begin{quote}
foldl and foldl' are the same except for their strictness properties, so if both
return a result, it must be the same.\autocite{fold-types}
\end{quote}
The strictness property is only relevant if the function is lazy in its first argument.
If this is the case, behavioural differences can be seen because foldl builds up a so
called `execution path' (nesting the called functions), while foldl' executes these
functions while traversing it already. An example of this is illustrated in
Appendix~\ref{appendix:foldl-strictness}.
To keep things simpler, Go will only have its versions of foldl and foldr, which
will both be strict --- the Haskell counterparts would thus be foldr and foldl'.\footnote{
If the behaviour from the normal foldl function is required, a workaround can
be applied in the Go version. See Appendix~\ref{appendix:foldl-go}}
The usage of these fold-functions is equal to the Haskell versions, where foldl's
arguments are switched in order.
\begin{listing}
\begin{gocode}
package main
import "fmt"
func main() {
sub := func(x, y int) int { return x - y }
fmt.Printf("%v\n", foldr(sub, 100, []int{10, 20, 30})) // -80
fmt.Printf("%v\n", foldl(sub, 100, []int{10, 20, 30})) // 40
}
\end{gocode}
\caption{Example usage of foldr and foldl in go}\label{code:fold-go}
\end{listing}
\subsection{Filter}
The filter function is the conceptually simplest higher-order function.
It takes a list and filters out all elements that are not matching
a given predicate.
This predicate usually is a function that takes said element and returns
a boolean if it should be kept or filtered.
A simple example:
\begin{listing}
\begin{gocode}
package main
import "fmt"
func main() {
smallerThan5 := func(x int) bool {
return x < 5
}
fmt.Println(filter(smallerThan5, []int{1, 8, 5, 4, 7, 3})) // [1, 4, 3]
}
\end{gocode}
\caption{Example usage of filter in Go}\label{code:filter-go}
\end{listing}

@ -0,0 +1,446 @@
To learn functional programming without a purely functional language, the
developer needs to know which statements are functional and which
would not exist or be possible in a purely functional language.
For this reason, a `functional checker' should be created. It should work
in a similar fashion to linters like `shellcheck', `go vet' or `gosimple'\footnote{
A list of Go linters can be found in golangci-lint\autocite{golangci-lint}.
}, with different `rules' that are reported upon. This tool will be named `funcheck'.
A set of rules should be compiled to identify common `non-functional' constructs
which should then be reported upon.
The first step is to define a set of rules.
\subsection{Functional Purity}\label{sec:func-purity}
The goal of funcheck is to report every construct that can not be considered
to be purely functional. As there is no agreed upon definition on what
functional purity is\autocite{functional-controversy}, the first step is to
define functional purity for the context of this thesis:
\begin{quote}
A style of building the structure and elements of computer programs that
treats all computation as the evaluation of mathematical functions. Purely
functional programming may also be defined by forbidding changing state and
mutable data.
Purely functional programming consists in ensuring that functions, inside
the functional paradigm, will only depend on their arguments, regardless of
any global or local state.\autocite{functional-purity-wiki}
\end{quote}
This definition roughly brakes down into two parts; immutability and function
purity. These parts and how they translate to Go will be discussed in the
following chapters.
\subsection{Forbidding mutability and changing state}\label{sec:mutability}
\newglossaryentry{copy-by-value}{name=copy by value, description={Copy by value
refers to the argument-passing style where the supplied arguments are
copied. To pass references in Go, the developer needs to use pointers
instead}}
Immutability refers to objects --- variables --- that are unchangeable. This means
that their state cannot be modified after it's creation and first assignment.
Many programming languages provide features for making variables immutable.
In Rust for example, variables are immutable by default. To explicitly declare
a mutable variable, the \mintinline{rust}|mut| keyword has to be used: \mintinline{rust}|let mut x = 5;|.
Java, in contrast, uses the \mintinline{java}|final| keyword:
\begin{quote}
A final variable can only be initialized once\autocite{final-java}
\end{quote}
`Only be initialized once' means that it cannot be reassigned later, effectively
making that variable immutable.
A caveat with Java's \mintinline{java}|final| keyword is that the immutability
is only tied to the reference of that object, not
it's contents (one may still change a field of an immutable object).
C and C++ have two features to achieve immutability, the \mintinline{c}|#define|
preprocessor and the \mintinline{c}|const| keyword.
The \mintinline{c}|#define| directive does not declare variables, but rather
works in a similar way to string replacement at compile time. These directives
can also be expressions. For example, this is a valid define statement:
\begin{ccode}
#define AGE (20/2)
\end{ccode}
However, because \mintinline{c}|#define| is just text substitution, these
identifiers are untyped.
The \mintinline{c}|const| qualifier specifies that a variable's value
will not be changed, making it immutable. This is effectively the equivalent
to Java's \mintinline{java}|final|.
Go has the \mintinline{go}|const| keyword too, and similar to C, constants can only be
characters, strings, booleans or numeric values\footnote{In contrast to C, Go does
have a boolean type}. A complex type --- a struct, interface or function --- cannot be constant.
This means that the programmer cannot write
\mintinline{go}|const x = MyStruct{A: a, B: b}| to make a struct immutable.
A solution to making variables
immutable is to explicitly not allow any mutations in a program, effectively
disallowing all reassignments.
To do this in Go, the simplest solution is
to disallow the assignment operator \mintinline{go}|=|, and only
allow it in combination with a declaration (\mintinline{go}|:=|).
This solution also has the side-effect that it makes it impossible to mutate
existing, complex data structures like maps and slices\footnote{By not
allowing assignments, elements can not be updated by
\mintinline{go}|s[0] = "zero"| / \mintinline{go}|m["key"] = "value"|.}.
There are additional operators that work in a similar way to the assignment
operator, for example \mintinline{go}|++|, \mintinline{go}|--| and
\mintinline{go}|+=|. These are all `hidden' assignments and will need to
be reported upon too.
Go being a \gls{copy-by-value} language, mutating existing variables
across functions works by passing pointers to these variables\footnote{
An example for this can be found in Appendix~\ref{appendix:mutation}.}.
When removing the regular assignment operators, the usage of pointers becomes
second nature, as it cannot be updated either way.
Technically, the only advantage that pointers have left, is that less memory has
to be copied\footnote{The pointer still has to be passed, and thus copied, to the
called function} if a variable's type is big enough\footnote{For example, it is
cheaper to copy an \mintinline{go}|int32| than to take address of it, copy that
(64 bit, on most systems) address and dereferencing it again}.
This optimisation is left to the developer.
In functional languages in contrast, this optimisation is usually left to the compiler
and there are no pointers at all in the language\footnote{Except for things like the `foreign
function interface' (FFI) in Haskell, which allows to call C functions from Haskell code}.
A feature not discussed so far is shadowing. Shadowing a variable in a different
scope is still possible by redeclaring it. As expected, even with the above
mentioned limitations, the rules for shadowing variables do not change. This
can be seen in Appendix~\ref{appendix:shadowing}.
\subsection{Pure functions}
A pure function is a function where the return value is only dependent on
the arguments. With the same arguments, the function should always return
the same values. The evaluation of the function is also not allowed to have
any `side effects', meaning that it should not mutate non-local variables or
references\footnote{This also includes `local static' variables, but Go does
not have a way to make variables `static'.}.
As discussed in the last Chapter~\ref{sec:mutability}, if reassignments
are not allowed, mutating global variables is not possible either.
If global state cannot be changed, it also cannot influence a function's return values.
As such, forbidding reassignments is an extremely simple solution to
ensure functional purity within the program. However, there is one
important aspect that the solution does not solve: interacting with the outside world.
\subsection{IO}
Network and file access, time, randomness, user input and sensors are all examples
of IO, things that interact with state outside of the program.
Input and Output in a program --- through whether channel it may be --- is
impure by design. Due to this, the Haskell language authors faced a difficult
challenge; how to add impure functions to an otherwise completely pure
language.
In a pure language, functions only depend on their arguments, have
no side effects and return a value computed from these arguments. Because
of this, the execution order of functions is not relevant, a function
can be executed whenever its return value is needed.
Due to this, the compiler can optimise the code, calling the functions
in a specific (or in no specific) order or omitting calls if their return
values are unused.
However, impure IO functions introduce some difficulties.
For example, one would expect that it is possible to write a trivial `writeFile'
function that takes a filename and a string with the contents for that file with
the function definition roughly being:
\begin{haskellcode}
writeFile :: String -> String
\end{haskellcode}
Supposed that this function could be called with
\mintinline{haskell}|writeFile "hello.txt" "Hello World"|. The function
does not return anything, or its return value, for example the number
of bytes that have been written to the file, is discarded on the call site.
As there is no dependency on that function anymore, the compiler assumes that
this function does not need to be executed at all --- it still expects all
functions to be pure (even if this is not the case in this example).
Being able to follow the purity guarantees, the compiler emits the call
to the writeFile function and the file never gets written.
Similarly, for getting user input:
\begin{haskellcode}
getChar :: Char
\end{haskellcode}
If this function is called multiple times, the compiler may reorder the
execution of these calls, again, because it expects the functions to be
pure, so the execution order should not matter:
\begin{haskellcode}
get2Chars = [getChar, getChar]
\end{haskellcode}
However, in this example, execution order is extremely important.
To solve this problem, Haskell introduced the IO monad, in which
all functions are wrapped with a `RealWorld' argument. So the
\mintinline{haskell}|getChar| example would be written as\footnote{
This is not the actual function header for getChar, only an illustration.
The actual function header of getChar is \mintinline{haskell}|getChar :: IO Char|.
}:
\begin{haskellcode}
getChar :: RealWorld -> (Char, RealWorld)
\end{haskellcode}
This can be read as `take the current RealWorld, do something with it,
and return a Char and a (possibly changed) RealWorld'\autocite{haskell-io}.
With this solution, the compiler cannot reorder or omit IO actions, ensuring
the correct execution of the program.
The IO monad is a sophisticated solution to work around the purity guarantees and
enables Haskellers to use impure functions in an otherwise completely pure language.
Put another way: the IO monad exists because of compiler optimisations, which in turn are
based on the assumption that everything is pure.
In Go, the compiler does not and can not make this assumption. There also
is no `pure' keyword to mark a function as such. For that reason, the
compiler cannot optimise as aggressively, and the whole IO problem does
not exist. However, in the context of this thesis, interacting with the outside world ---
using IO-functions --- means that functional purity cannot be guaranteed anymore.
Haskell's solution to this issue is relatively complex, and while it may be applicable
to Go, it would require massively rewriting Go's standard library. Furthermore,
the IO monad does not make impure functions magically pure. Rather, it
clearly marks functions as impure.
Another issue, apart from the amount of work that would be needed, is that
the goal is to provide an easy introduction to functional programming.
IO, as one may see in these examples, is one of the hardest topics.
For those reasons, although it may violate the functional purity requirements,
the underlying issue with IO will be ignored. This means that the programmer
will still be able to use IO functions as in regular Go programs.
\subsection{Assignments in Go}
As described in Section~\ref{sec:mutability}, the only check that needs
to be done is that there are no reassignments in the code. There are a few
exceptions to this rule, which will be covered later. First, it is important to have
a few examples and test cases to be clear on what should be reported.
To declare variables in Go, the \mintinline{go}|var| keyword is used.
The var keyword needs to be followed by one or more identifiers and maybe
types or the initial value. These are all valid declarations:
\begin{listing}
\begin{gocode}
var i int
var U, V, W float64
var k = 1
var x, y float32 = -1, -2
\end{gocode}
\caption{Go Variable Declarations}
\end{listing}
What can be seen in this example is that the type of the variable can be
deducted automatically\footnote{The compiler will infer the type at compile
time. That operation is always successful, although it may not be what
the programmer desires. For example, \mintinline{go}|var x = 5| will
always result in \mintinline{go}|x| to be of type \mintinline{go}|int|.},
or be specified explicitly.
However, the notation \mintinline{go}|var k = 1| is seldomly seen. This
is due to the fact that there is a second way to declare and initialise
variables to a specific value, the `short variable declaration' syntax:
\begin{gocode}
k := 1
\end{gocode}
\begin{quote}
It is shorthand for a regular variable declaration with initializer expressions but no types:
\begin{bnfcode}
"var" IdentifierList = ExpressionList .
\end{bnfcode}
\autocite{short-hand-decl}
\end{quote}
In practice, the short variable declaration is used more often due to the
fact that there is no need to specify the type of the variable manually and
is shorter than its counterpart \mintinline{go}|var x = y|.
Go also has increment, decrement and various other operators to reassign
variables. Most of the operators that take a `left' and `right' expression
also have a short-hand notation to reassign the value back to the variable,
for example\footnote{This is a non-exhaustive list of operators. A complete listing
of operators can be found in the Go language spec\autocite{spec-operators}.}:
\begin{listing}
\begin{gocode}
var x = 5
x += 5 // equal to x = x + 5
x %= 3 // equal to x = x % 3
x <<= 2 // equal to x = x << 2 (bit-shift)
\end{gocode}
\caption{Go Assignment Operators}
\end{listing}
All these operators are reassigning values and should be reported.
However, as mentioned in the beginning of this chapter, there are a few exceptions
to this rule:
\subsubsection{Function Assignments}\label{sec:func-reassign}
A variable declaration brings an identifier into scope. The Go Language Specification
defines this scope according to the following rule:
\begin{quote}
The scope of a constant or variable identifier declared inside a function begins
at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable
declarations) and ends at the end of the innermost containing block.
\autocite{spec-scope}\end{quote}
This definition holds an important caveat for function definitions:
\begin{quote}
The scope [...] begins \textbf{at the end} of the ConstSpec or VarSpec [...].
\end{quote}
This means that when defining a function, the functions identifier is not
in scope within that function:
\begin{listing}
\begin{gocode}
func X() {
f := func() {
f() // <- 'f' is not in scope yet.
}
}
\end{gocode}
\caption{Go scoping issue with recursive functions}
\end{listing}
In the above example, the function \mintinline{go}|f| cannot be called recursively. This is due
to the fact that the identifier \mintinline{go}|f| is not in scope at \mintinline{go}|f|'s definition.
Instead, it only enters scope after the closing brace of function \mintinline{go}|f|.
This cannot be changed within the compiler without touching a lot of the scoping
rules and changing these scoping rules may have unintended side effects. To exemplify,
a naive solution to the issue would be to bring the identifier into scope right after the
assignment operator (\mintinline{go}|=|). However, this would introduce further
edge cases, as for example \mintinline{go}|x := x|, and extra measures would have
to be taken to make such constructs illegal again.
However, there is a simple, although verbose solution to this problem: The function
has to be declared in advance:
\begin{listing}
\begin{gocode}
func X() {
var f func() // f enters scope after this line
f = func() {
f() // this is allowed, as f is in scope
}
}
\end{gocode}
\caption{Fixing the scope issue on recursive functions}
\end{listing}
This exception will need to be allowed by the assignment checker, as recursive functions
are one of the building blocks in functional programming.
\subsubsection{Multiple Assignments}\label{sec:multi-assign}
\newglossaryentry{ebnf}{name=EBNF, description={Extended Backus-Naur Form, an extended version of the `Backus-Naur
Form, a notation technique to describe programming language syntax}}
As discussed at the beginning of this Chapter, the short variable declaration brings
a variable into scope and assigns it to a given expression (value). It is also
possible to declare multiple variables at once, as can be seen in the \gls{ebnf}
notation:
\begin{listing}
\begin{bnfcode}
ShortVarDecl = IdentifierList ":=" ExpressionList .
\end{bnfcode}
\end{listing}
This clearly shows that both left- and right-hand side take a list, meaning one or more
elements, making a statement like \mintinline{go}|x, y := 1, 2| valid\footnote{This also
holds true for the \mintinline{go}|var| keyword}.
However, there is an important note to be found in the language specification:
\begin{quote}
Unlike regular variable declarations, a short variable declaration may redeclare
variables provided they were originally declared earlier in the same block (or
the parameter lists if the block is the function body) with the same type, and
at least one of the non-blank\footnote{The blank identifier (\mintinline{go}|_|)
discards a value; \mintinline{go}|x, _ := f()|} variables is new. As a consequence, redeclaration
can only appear in a multi-variable short declaration. Redeclaration does not
introduce a new variable; it \textbf{just assigns a new value to the original}\autocite{short-hand-decl}.
\begin{gocode}
field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset) // redeclares offset
\end{gocode}
\end{quote}
This should not be allowed, as the programmer can introduce mutation by redeclaring
already existing variables in a short variable declaration.
\subsubsection{For Loops}
Although the aforementioned rules cover almost every case of reassignment, they miss
one of the most important parts: For loops.
In Go, there is only one looping construct, the \mintinline{go}|for| loop. However, it can
be used in roughly four different ways:
The infinite loop:
\begin{gocode}
for {
// ...
}
\end{gocode}
The while loop:
\begin{gocode}
for x == true { // boolean expression
// ...
}
\end{gocode}
The regular C-style for loop:
\begin{gocode}
for x := 0; x < 10; x++ {
// ...
}
\end{gocode}
And the range loop, which allows to range (iterate) over slices, maps and channels\footnote{Channels
have not been discussed in this thesis, but are an important building block in Go's concurrency
features. They work similarly to Unix Pipes (`|'), in that they allow to send data in and receive
it on the other `side'. A \mintinline{go}|range| receives as long as the channel is not closed.}:
\begin{gocode}
for idx, elem := range []int{1,8,5,4} {
// ...
}
\end{gocode}
Range returns two values, both of which can be omitted\footnote{The values can be omitted
by using the blank identifier `\_'. Skipping the index is thus
\mintinline{go}|_, elem := range s|, while skipping the value with
\mintinline{go}|i, _ := range s| which is equal to just \mintinline{go}|i := range s|.}. When
ranging over a slice, the index and a copy of the element at that index is returned. For
maps, the key and a copy of the corresponding value is returned.
Except of the C-style for loop, the loops do not have a reassignment statement when
converted to the AST. For this reason, they would not be detected by the previously defined rule and thus
the programmer could use them.
However, issues emerge when having a closer look at the loop constructs.
The \mintinline{go}|range| loop needs to keep track of the element, and it does so (internally)
by using a pointer. This results in a (internal) reassignment.
The regular C-style for loop and the `while' loop do not work at all without reassignments.
Although in the while-loop the reassignment happens at another place, most probably within the loop,
it is easier for the user if a report on the loop construct is generated instead.
The infinite loop does not contain any reassignments and is thereby be legal by the
definition of the reassignment rule. Because of this, it should not be reported.
All other for-loops need to be reported as they contain internal reassignments.

@ -0,0 +1,7 @@
\section{Implementing the new built-in functions}
\input{chapters/41_builtins.tex}
\clearpage
\section{Functional Check}
\input{chapters/45_funcheck.tex}

@ -0,0 +1,120 @@
\subsection{Required Steps}
Adding a built-in function to the Go language requires a few more steps than just
adding support within the compiler. While it would technically be enough to
support the translation between Go code and the compiled binary, there would be
no visibility for a developer that there is a function which could be used.
For a complete implementation, the following steps are necessary:
\begin{itemize}
\item Adding the Godoc\autocite{godoc} that describes the function and it's usage
\item Adding type-checking support in external packages for tools like
Gopls\footnote{Gopls is Go's official language server implementation\autocite{gopls}.}
\item Adding the implementation within the internal\footnote{
`internal' packages can only be imported by other packages that
are rooted at the parent of the `internal' directory. It is used to
make specific packages not importable in order to decrease potential API surface\autocite{internal-packages}.
}
package of the compiler
\begin{itemize}
\item Adding the \gls{ast} node type
\item Adding type-checking for that node type
\item Adding the AST traversal (`walk') for that node type, translating it
to AST nodes that the compiler already knows and can translate
to built-in runtime-calls or \gls{ssa}
\end{itemize}
\end{itemize}
The Go source code that is relevant for this thesis can be classified into three different
types. One is the Godoc --- the documentation for the new built-in functions. The
other two are the `public' and the `private' implementation of these built-ins.
The `private' implementation is located within the
\textit{src/cmd/compile/internal} package\autocite{internal-packages}. Because it
is an internal package, it can only
be used by the packages in \textit{src/cmd/compile}, which contain the
implementation of the compiler itself.
When calling
\begin{bashcode}
$> go build .
\end{bashcode}
the compiler is invoked indirectly
through the main `go' binary. To directly invoke the compiler,
\begin{bashcode}
$> go tool compile
\end{bashcode}
can be used.
Everything that is not in \textit{src/cmd/compile} is referred to as the `public'
part of the compiler in this thesis. The `public' parts are used by external
tools, for example Gopls, for type-checking, source code validation and
analysis.
\subsection{Adding the Godoc}
In Go, documentation is generated directly from comments within the source code
\autocite{godoc}. This also applies to built-in functions in the compiler, which
have a function stub to document their behaviour\autocite{godoc-builtin}, but
no implementation, as that is done in the compiler\autocite{builtin-impl}.
The documentation for built-ins should be as short and precise as possible.
The usage of `Type' and `Type1' has been decided based on other built-ins
like `append' and 'delete'.
The function headers are derived from their Haskell counterparts, adjusted
to the Go nomenclature.
\begin{code}
\gofilerange{../work/go/src/builtin/builtin.go}{begin-newbuiltins}{end-newbuiltins}%
\caption{Godoc for the new built-in functions\autocite{new-builtins-godoc}}
\end{code}
\subsection{Public packages}
To enable tooling support for the new built-in functions, they have to be
registered in the `go/*' packages. The only package that is affected by new
built-ins is `go/types'.
\begin{quote}
Note that the `go/*` family of packages, such as `go/parser` and `go/types`,
have no relation to the compiler. Since the compiler was initially written in C,
the `go/*` packages were developed to enable writing tools working with Go code,
such as `gofmt` and `vet`.\autocite{compiler-readme}
\end{quote}
In the `types' package, the built-ins have to be registered as such and as
`predeclared' functions:
\begin{code}
\gofilerange{../work/go/src/go/types/universe.go}{start-builtin}{end-builtin}%
\gofilerange{../work/go/src/go/types/universe.go}{start-predeclared}{end-predeclared}%
\caption{Registering new built-in functions\autocite{new-builtins-universe}}
\end{code}
This registration defines the type of the built-in --- they are all expressions,
as they return a value --- and the number of arguments.
After that, the type-checking and its associated tests have been implemented, but
are not shown here. The implementation can be located in the `src/go/types' package
in the files `builtins.go', `builtins\_test.go' and `universe.go' See the git
diff\autocite{ba-go1-14-thesis-diff} to view the changes that have been made.
This concludes the type-checking for external tools.
`gopls' can be compiled against these changed public packages\footnote{
See Appendix~\ref{appendix:build-gopls} for instructions on how to build Gopls.
} and will then return errors if the wrong types are used. For example, when trying
to prepend an integer to a string slice:
\begin{gocode}
package main
import "fmt"
func main() {
fmt.Println(prepend(3, []string{"hello", "world"}))
}
\end{gocode}
Gopls will report a type-checking error:
\begin{bashcode}
$ gopls check main.go
/tmp/playground/main.go:6:22-23: cannot convert 3 (untyped int constant) to string
\end{bashcode}
\subsection{Private packages}
\input{chapters/42_functions.tex}

@ -0,0 +1,203 @@
In the private packages - the actual compiler - the expressions have to be
type-checked, ordered and transformed.
The type-checking process is similar to the one executed for external tools.
Furthermore, during the type-checking
process, the built-in function's return types are set and node types
may be converted, if possible and necessary.
An operation may expect it's arguments to be in \mintinline{go}|node.Left|
and \mintinline{go}|node.Right|, which means type-checking will also need
to move the argument nodes from their default location in
\mintinline{go}|node.List| to \mintinline{go}|node.Left| and
\mintinline{go}|node.Right|.
Ordering ensures the evaluation order and re-orders expressions. All of
the new built-in functions will be evaluated left-to-right and there are no
special cases to handle.
Transforming means changing the AST nodes from the built-in operation to
nodes that the compiler knows how to translate to SSA. The actual algorithm
that these functions use cannot be implemented in normal Go code, they have to be
translated directly to AST nodes and statements.
There are more steps to compiling Go code, for example escape-checking,
SSA conversion and a lot of optimisations. These are not necessary to
implement and do not have a direct relation to the new built-ins.
The algorithms and part of the implementations for the built-in
functions are covered in the following chapters\footnote{
To see the full implementation, the git diff can be viewed\autocite{ba-go1-14-thesis-diff}.
}.
\subsubsection{fmap}\label{ch:impl-fmap}
To make the implementation in the AST easier, the algorithm will first be
developed in Go, and then translated. Implementing fmap in Go is relatively
simple:
\begin{listing}
\begin{gocode}
func fmap(fn func(Type) Type1, src []Type) (dest []Type1) {
for _, elem := range src {
dest = append(dest, fn(elem))
}
return dest
}
\end{gocode}
\caption{fmap implementation in Go}\label{code:fmap-go}
\end{listing}
However, there is room for improvement within that function. Instead
of calling \mintinline{go}|append| at every iteration of the loop, the slice can
be allocated with \mintinline{go}|make| at the beginning of the function. Thus,
calls to grow the slice at runtime can be saved.
\begin{listing}
\begin{gocode}
func fmap(fn func(Type) Type1, src []Type) []Type1 {
dest := make([]Type1, len(src))
for i, elem := range src {
dest[i] = fn(elem)
}
return dest
}
\end{gocode}
\caption{Improved implementation of fmap}\label{code:fmap-go-improved}
\end{listing}
This algorithm can be translated to the following AST node:
\begin{code}
\gofilerange{../work/go/src/cmd/compile/internal/gc/walk.go}{start-fmap-header}{end-fmap-header}%
\caption{fmap AST translation\autocite{fmap-walk-implementation}}
\end{code}
The full AST code is not displayed here as, although the algorithm is simple, the AST translation
is not as concise and more than 10 times the size. A demonstration on how a translation looks like
will be introduced in Section~\ref{ch:ast-traversal}.
The full implementation of this function is referenced in the code block's caption.
\subsubsection{prepend}
The general algorithm for `prepend' is:
\begin{listing}
\begin{gocode}
func prepend(elem Type, slice []Type) []Type {
dest := make([]Type, 1, len(src)+1)
dest[0] = elem
return append(dest, slice...)
}
\end{gocode}
\caption{prepend implementation in Go}
\end{listing}
The call to \mintinline{go}|make(...)| creates a slice with the length of 1 and the capacity
to hold all elements of the source slice, plus one. By allocating the slice with the full
length, another slice allocation within the call to \mintinline{go}|append(...)| is saved.
The element to prepend is added as the first element of the slice, and append will then
copy the `src' slice into `dest'.
The implementation within `walkprepend' reflects these lines of Go code, but
as AST nodes:
\begin{code}
\gofilerange{../work/go/src/cmd/compile/internal/gc/walk.go}{start-prepend-header}{end-prepend-header}%
\caption{prepend AST translation\autocite{prepend-walk-implementation}}
\end{code}
\subsubsection{foldr and foldl}
As outlined in Chapter~\ref{sec:fold}, there will be two fold functions;
foldr and foldl. foldr behaves exactly like its Haskell counterpart,
while foldl behaves like foldl' in Haskell.
While the fold algorithms are most obvious when using recursion, due to
performance considerations, an imperative implementation has been chosen:
\begin{listing}
\begin{gocode}
func foldr(fn func(Type, Type1) Type1, acc Type1, slice []Type) Type1 {
for i := len(s) - 1; i >= 0; i-- {
acc = fn(s[i], acc)
}
return acc
}
func foldl(fn func(Type1, Type) Type1, acc Type1, slice []Type) Type1 {
for i := 0; i < len(s); i++ {
acc = f(acc, s[i])
}
return acc
}
\end{gocode}
\caption{fold implementation in Go}
\end{listing}
The code further clarifies the differences between the two different folds;
the slice is processed in reverse order for foldr (as it would be if this
algorithm would have been implemented with recursion), and the order of
arguments to the fold function is switched.
The AST walk translates fold to:
\begin{code}
\gofilerange{../work/go/src/cmd/compile/internal/gc/walk.go}{start-fold-header}{end-fold-header}%
\caption{fold AST translation\autocite{fold-walk-implementation}}
\end{code}
\subsubsection{filter}\label{ch:impl-filter}
Being a slice-manipulating function, filter also needs to traverse the whole
slice in a for-loop. However, compared to the other newly built-in functions,
the size for the target slice is unknown until all items have been traversed,
which is why filter does not allow for the same optimisations as the other
functions.
\begin{code}
\begin{gocode}
func filter(f func(Type) bool, s []Type) (dst []Type) {
for i := range s {
if f(s) {
dst = append(dst, s[i])
}
}
}
\end{gocode}
\caption{filter implementation in Go}
\end{code}
And the same algorithm, but translated to AST statements:
\begin{code}
\gofilerange{../work/go/src/cmd/compile/internal/gc/walk.go}{start-filter-header}{end-filter-header}%
\caption{filter AST translation\autocite{filter-walk-implementation}}
\end{code}
\subsubsection{Writing the AST traversal}\label{ch:ast-traversal}
The previous chapters have all shown the function headers of the `walk' functions
that are used to traverse and rewrite the new built-ins. To illustrate how the
actual implementation of such an algorithm looks like in these functions, we
provide a small example here. The full implementation of these algorithms can
be viewed at the git diff\autocite{ba-go1-14-thesis-diff}.
This demonstration shows the translation of the statement
\begin{gocode}
filtered := make([]T, 0)
\end{gocode}
into AST nodes, or rather the construction of these AST nodes.
The type is simply a placeholder, as the AST construction uses the source slice's
type. This source slice is another AST node of which the type can be obtained from.
\begin{code}
\begin{gocode}
// create the AST node for the first argument that is
// being passed to `make', the type:
makeType := nod(OTYPE, nil, nil)
makeType.Type = source.Type // use the type of the slice
// create the make(...) AST node
makeDest := nod(OMAKE, nil, nil)
// add the arguments (the type and an int constant 0
makeDest.List.Append(makeType, nodintconst(0)) // make([]<T>, 0))
// create the "variable" where the result of make will be stored
filtered := temp(source.Type)
// the final AST node that contains the statement
// filtered = make([]<T>, 0)
final := nod(OAS, filtered, makeDest))
\end{gocode}
\caption{Illustrating the difference between Go code and it's AST code}
\end{code}

@ -0,0 +1,270 @@
As discussed in Chapter~\ref{sec:funcheck-theory}, to assist writing purely
functional code, a linter needs to be implemented that detects reassignments within
a Go program.
To get a grasp on the issues this linter should report, the first step
is to capture some examples, cases that should be matched against.
\subsection{Examples}
The simplest cases are standalone reassignments and assignment operators:
\begin{gocode}
x := 5
x = 6 // forbidden
// or
var y = 5
y = 6 // forbidden
y += 6 // forbidden
y <<= 2 // forbidden
y++ // forbidden
\end{gocode}
Where the statements with a \mintinline{go}|// forbidden
|comment should be reported.
Adding block scoping to this, shadowing the old variable needs to be allowed:
\begin{gocode}
x := 5
{
x = 6 // forbidden, changing the old value
x := 6 // allowed, as this shadows the old variable
}
\end{gocode}
What should be illegal is to declare the variable first and then assign a
value to it:
\begin{gocode}
var x int
x = 6 // forbidden
\end{gocode}
The exception here are functions, as they need to be declared first in order
to recursively call them:
\begin{gocode}
var f func()
f = func() {
f()
}
\end{gocode}
Furthermore, the linter also needs to be able to handle multiple variables
at once:
\begin{gocode}
var f func()
x, f, y := 1, func() { f() }, 2
\end{gocode}
Loops should be reported too, as they are using reassignments internally:
\begin{gocode}
for i := 0; i < 5; i++ { // forbidden
for i != 3 { // forbidden
for { // allowed
// ...
}
}
}
\end{gocode}
All the aforementioned examples and more can be found in the test cases for funcheck\autocite{funcheck-examples}.
\subsection{Building a linter}
The Go ecosystem already provides an official library for building code analysis tools,
the `analysis' package from the Go Tools repository\autocite{go-analysis}. With this package,
implementing a static code analyser is reduced to writing the actual AST node analysis.
To define an analysis, a variable of type \mintinline{go}|*analysis.Analyzer| has to be declared:
\begin{gocode}
var Analyzer = &analysis.Analyzer{
Name: "assigncheck",
Doc: "reports reassignments",
Run: func(*analysis.Pass) (interface{}, error)
}
\end{gocode}
The necessary steps are now adding the `Run' function and registering the analyser
in the \mintinline{go}|main()| function.
The `Run' function takes an \mintinline{go}|*analysis.Pass| type. The Pass provides
information about the package that is being analysed and some helper-functions to report
diagnostics.
With `analysis.Pass.Files` and the help of the `go/ast` package, traversing the syntax
tree of every file in a package becomes extremely convenient:
\begin{gocode}
for _, file := range pass.Files {
ast.Inspect(file, func(n ast.Node) bool {
// node analysis here
})
}
\end{gocode}
To implement funcheck as described, five different AST node types need to be
taken care of. The simpler ones are
\mintinline{go}|*ast.IncDecStmt|, \mintinline{go}|*ast.ForStmt| and \mintinline{go}|*ast.RangeStmt|.
An `IncDecStmt' node is a \mintinline{go}|x++| or \mintinline{go}|x--|
expression and should always be reported.
`ForStmt' and `RangeStmt' are similar; a `RangeStmt' is a `for' loop with the
\mintinline{go}|range| keyword instead of an init-, condition- and post-statement.
Both of these loop-types need to be reported explicitly as they do not show up
as reassignments in the AST.
Thus, the basic building block for the AST traversal is the following \mintinline{go}|switch|
statement:
\begin{code}
\gofilerange{../work/funcheck/assigncheck/assigncheck.go}{start-basictypes}{end-basictypes}%
\caption{Handling the basic AST types in funcheck\autocite{funcheck-ast-types}}
\end{code}
The remaining two node types are \mintinline{go}|*ast.DeclStmt| and \mintinline{go}|*ast.AssignStmt|.
They are not as simple to handle, which is why they are covered in their own chapters.
\subsection{Detecting reassignments}
To recapitulate, the goal of this step is to detect all assignments except blank identifiers
(discarded values cannot be mutated) and function literals, if the function is declared in the
last statement\footnote{This rule is to simplify the logic of the checker and make it easier
for developers to read the code. It means that no code may be between \mintinline{go}|var f func|
and \mintinline{go}|f = func() { ... }|.}.
To detect such reassignments, funcheck iterates over all identifiers on the left-hand side
of an assignment statement.
On the left-hand side of an assignment is a list of expressions. These expressions can be
identifiers, index expressions (\mintinline{go}|*ast.IndexExpr|, for map and slice access),
a `star expression' (\mintinline{go}|*ast.StarExpr|\footnote{star expressions
are expressions that are prefixed by an asterisk, dereferencing a pointer. For example
\mintinline{go}|*x = 5|, if \mintinline{go}|x| is of type \mintinline{go}|*int|.}) or others.
If the expression is not an identifier, the assignment must be a reassignment, as all non-identifier
expressions contain an already declared identifier. For example, the slice index expression
\mintinline{go}|s[5]| is of type \mintinline{go}|*ast.IndexExpr|:
\begin{gocode}
// An IndexExpr node represents an expression followed by an index.
IndexExpr struct {
X Expr // expression
Lbrack token.Pos // position of "["
Index Expr // index expression
Rbrack token.Pos // position of "]"
}
\end{gocode}
Where \mintinline{go}|IndexExpr.X| is our identifier `s' (of type \mintinline{go}|*ast.Ident|)
and a \mintinline{go}|IndexExpr.Index| is \mintinline{go}|5| (of type \mintinline{go}|*ast.BasicLit|).
As these nested identifiers already need to be declared beforehand (else they could not be used
in the expression), all expressions on the left-hand side of an assignment that are not identifiers
are reassignments.
Identifiers are the only expressions that can occur in declarations and reassignments. A naive
approach would be to check for the colon in a short variable declaration (\mintinline{go}|:=|).
However, as touched upon in Chapter~\ref{sec:multi-assign}, even short variable declarations may
contain redeclarations, if at least one variable is new.
Thus, another approach is needed.
Every identifier (an AST node with type \mintinline{go}|*ast.Ident|) contains an object\footnote{`An
object describes a named language entity such as a package, constant, type, variable,
function (incl. methods), or a label'\autocite{go-ast-object}.} that links to the declaration.
This declaration, of whatever type it may be, always has a position (and a corresponding function
to retrieve that position) in the source file.
A reassignment is detected if an identifier's declaration position does not match the assignment's
position (indicating that the variable is being assigned at a different place to where it is
declared).
This is illustrated in the code block~\ref{code:assign-pos}. What can be clearly seen is that in
the assignment \mintinline{go}|y = 3|, \mintinline{go}|y|'s declaration refers to the position
of the first assignment \mintinline{go}|x, y := 1, 2|, the position where \mintinline{go}|y| has
been declared.
\begin{listing}
\begin{gocode}
Assignment "x, y := 1, 2": 2958101
Ident "x": 2958101
Decl "x, y := 1, 2": 2958101
Ident "y": 2958104
Decl "x, y := 1, 2": 2958101
Assignment "y = 3": 2958115
Ident "y": 2958115
Decl "x, y := 1, 2": 2958101
\end{gocode}
\caption{Illustration of an assignment node and corresponding positions\autocite{ast-positions}\label{code:assign-pos}}
\end{listing}
As this technique works on an identifier level, multi-variable declarations or assignments
can be verified without any additional effort.
If a variable in a short variable declaration is being reassigned, the variable's `Declaration'
field will point to the original position of its declaration, which can be easily detected
(as shown in code block~\ref{code:assign-pos}).
\subsection{Handling function declarations}
In contrast to all other variable types, function variables may be `reassigned' once.
As discussed in Chapter~\ref{sec:func-reassign}, this is to allow recursive function
literals. Detecting and not reporting these assignments is a two-step process, as two
consecutive AST nodes need to be inspected.
The first step is to detect function declarations; statements of the form
\mintinline{go}|var f func() |. Should such a statement be encountered,
its position is saved for the following AST node.
In the consecutive AST node it is ensured that, if the node is an assignment and
the assignee identifier is of type function literal, the position matches the
previously saved one.
The position of the declaration and AST node structure can be seen in~\ref{code:func-reassign}
\begin{listing}
\begin{gocode}
Declaration "var f func() int": 2958142
Ident "f func() int": 2958146
Assignment "f = func() int { return y }": 2958160
Ident "f": 2958160
Decl "f func() int": 2958146
\end{gocode}
\caption{Illustration of a function literal assignment\autocite{ast-positions}\label{code:func-reassign}}
\end{listing}
With this technique it is possible to exempt functions from the reassignment rule.
\subsection{Testing Funcheck}
The analysis-package is distributed with a sub-package `analysistest'. This package makes
it extremely simple to test a code analysis tool.
By providing test data and the expected messages from funcheck in a structured way, all
that is needed to test funcheck is:
\begin{code}
\begin{gocode}
package assigncheck
import (
"testing"
"golang.org/x/tools/go/analysis/analysistest"
)
func TestRun(t *testing.T) {
analysistest.Run(t, analysistest.TestData(), Analyzer)
}
\end{gocode}
\caption{Testing a code analyser with the `analysistest' package}
\end{code}
The library expects the test data in the current directory in a folder named `testdata' and
then spawns and executes the analyser on the files in that folder. Comments in those files
are used to describe the expected message:
\begin{gocode}
x := 5
fmt.Println(x)
x = 6 // want `^reassignment of x$`
fmt.Println(x)
\end{gocode}
This will ensure that on the line \mintinline{go}|x = 6| an error message is reported that says
`reassignment of x'.

@ -0,0 +1,300 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
\section{Demonstration of the new built-in functions}
The new built-in functions can be used in the same manner as the existing built-ins like
\mintinline{go}|append|. This example serves as a demonstration by modifying a slice
of integers, although they can be used to modify a slice of any type.
\begin{code}
\begin{gocode}
package main
import (
"fmt"
"strconv"
)
// Counterpart to Haskell's `derive Show` through code generation
//go:generate stringer -type parity
type parity int
const even parity = 0
const odd parity = 1
// shouldBe returns a function that returns true if an int is of the
// given parity
func shouldBe(p parity) func(i int) bool {
return func(i int) bool {
return i%2 == int(p)
}
}
func main() {
lst := []int{1, 2, 3, 4, 5}
lstMult := fmap(func(i int) int { return i * 5 }, prepend(0, lst))
addToString := func(s string, i int) string {
return s + strconv.Itoa(i) + " "
}
// fold over even / odd numbers and add them to a string
evens := foldl(addToString, even.String()+": ",
filter(shouldBe(even), lstMult))
odds := foldl(addToString, odd.String()+": ",
filter(shouldBe(odd), lstMult))
fmt.Println(evens, odds) // even: 0 10 20 odd: 5 15 25
}
\end{gocode}
\caption{Demonstration of the new built-in functions\label{code:funcexample}}
\end{code}
\section{Refactoring the Prettyprint Package}
\newglossaryentry{stdout}{name=stdout, description={Standard Output, the default
output stream for programs}}
The code blocks~\ref{code:assign-pos} and~\ref{code:func-reassign} have been
generated by a small package `prettyprint' contained in the funcheck repository.
To see how the newly built-in functions and funcheck can be used, this `prettyprint' package
can be refactored to a purely functional implementation.
The current version of the package is written in what could be considered idiomatic
Go\footnote{
There is no exact definition of what idiomatic Go is, so this interpretation
could be challenged. It is idiomatic Go code to the author.
}.
The prettyprinter is based on the same framework as assigncheck\footnote{Assigncheck
is the main package for funcheck and checks the reassignments}, but instead
of reporting anything, it prints AST information to \gls{stdout}.
Similarly to assigncheck, the main logic of the package is within a
function literal that is being passed to the \mintinline{go}|ast.Inspect|
function.
Prettyprint only checks two AST node types, \mintinline{go}|*ast.DeclStmt|
and \mintinline{go}|*ast.AssignStmt| (declarations and assignments).
For example, for the program
\begin{gocode}
package main
import "fmt"
func main() {
x, y := 1, 2
y = 3
fmt.Println(x, y)
}
\end{gocode}
the following AST information is printed:
\begin{gocode}
Assignment "x, y := 1, 2": 2958101
Ident "x": 2958101
Decl "x, y := 1, 2": 2958101
Ident "y": 2958104
Decl "x, y := 1, 2": 2958101
Assignment "y = 3": 2958115
Ident "y": 2958115
Decl "x, y := 1, 2": 2958101
\end{gocode}
To refactor it to a purely functional version, funcheck can be used to
list reassignments:
\begin{bashcode}
$> funcheck .
prettyprint.go:20:2: internal reassignment (for loop) in "for _, file := range pass.Files { ... }"
prettyprint.go:42:2: internal reassignment (for loop) in "for i := range decl.Specs { ... }"
prettyprint.go:67:2: internal reassignment (for loop) in "for _, expr := range as.Lhs { ... }"
\end{bashcode}
As can be seen in the output, the package uses 3 \mintinline{go}|for| loops to range over
slices. However, there are no other reassignments of variables in the code.
The code to print declarations, which causes the second lint message, is as shown in code block~\ref{code:decl-printing}.
\begin{code}
\begin{gocode}
func checkDecl(as *ast.DeclStmt, fset *token.FileSet) {
fmt.Printf("Declaration %q: %v\n", render(fset, as), as.Pos())
decl, ok := as.Decl.(*ast.GenDecl)
if !ok {
return
}
for i := range decl.Specs {
val, ok := decl.Specs[i].(*ast.ValueSpec)
if !ok {
continue
}
if val.Values != nil {
continue
}
if _, ok := val.Type.(*ast.FuncType); !ok {
continue
}
fmt.Printf("\tIdent %q: %v\n", render(fset, val), val.Names[0].Pos())
}
}
\end{gocode}
\caption{Pretty-printing declarations in idiomatic Go\label{code:decl-printing}}
\end{code}
To convert this for-loop appropriately, the new built-in `foldl' can be used.
To recapitulate, the `foldl' function is being defined as:
\begin{gocode}
func foldl(fn func(Type1, Type) Type1, acc Type1, slice []Type) Type1
\end{gocode}
As `foldl' requires a return type, a dummy type `null" can be introduced, which
is just an empty struct:
\begin{gocode}
type null struct{}
\end{gocode}
Now the code within the for loop can be used to create a function literal:
\begin{gocode}
check := func(_ null, spec ast.Spec) (n null) {
// implementation
}
\end{gocode}
There are two subtleties in regards to the introduced null type:
First, the null value that is being passed as an argument is being discarded
by the use of an empty identifier.
Secondly, the return value is `named', which means the variable `n' is
already declared in the function block. Because of this, `naked returns' can
be used, so there is no need to specify which variable is being returned.
The code snippet~\ref{code:decl-printing} can be translated to:
\begin{code}
\begin{gocode}
func checkDecl(as *ast.DeclStmt, fset *token.FileSet) {
fmt.Printf("Declaration %q: %v\n", render(fset, as), as.Pos())
check := func(_ null, spec ast.Spec) (n null) {
val, ok := spec.(*ast.ValueSpec)
if !ok {
return
}
if val.Values != nil {
return
}
if _, ok := val.Type.(*ast.FuncType); !ok {
return
}
fmt.Printf("\tIdent %q: %v\n", render(fset, val), val.Names[0].Pos())
return
}
if decl, ok := as.Decl.(*ast.GenDecl); ok {
_ = foldl(check, null{}, decl.Specs)
}
}
\end{gocode}
\caption{Pretty-printing declarations in functional Go}
\end{code}
The for-loop has been replaced by a `foldl', where a function closure
that contains the actual processing is passed.
While this still looks similar to the original example, this is mostly due to
the `if' statements. In Haskell, pattern matching would be used and nil checks
could be omitted entirely. Also, as Haskell's type system is more advanced, the
handling of those types would be different too.
However, the goal of this thesis is to make functional code look more familiar
to programmers that are used to imperative code.
And while it may not look like it, the code does not use any mutation of
variables\footnote{Libraries may do, but the scope is not to rewrite any existing
libraries.}, for loops or global state. Therefore, it can be concluded that this
snippet is purely functional as per the definition from Chapter~\ref{sec:func-purity}.
\section{Quicksort}
In Chapter~\ref{code:haskell-quicksort}, a naive implementation of the Quicksort sorting
algorithm has been introduced.
Implementing this algorithm in Go is now straightforward and the similarities between
the Haskell implementation and the functional Go implementation are striking:
\begin{listing}
\begin{gocode}
func quicksort(p []int) []int {
if len(p) == 0 {
return []int{}
}
lesser := filter(func(x int) bool { return p[0] > x }, p[1:])
greater := filter(func(x int) bool { return p[0] <= x }, p[1:])
return append(quicksort(lesser), prepend(p[0], quicksort(greater))...)
}
\end{gocode}
\begin{haskellcode}
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
\end{haskellcode}
\caption{Quicksort implementations compared}
\end{listing}
Again, the Go implementation bridges the gap between being imperative and functional,
while still being obvious about the algorithm.
Furthermore, as expected, when inspecting the code with funcheck, no non-functional
constructs are reported.
\section{Comparison to Java Streams}
In Java 8, concepts from functional programming have been introduced to the language.
The major new feature was Lambda Expressions --- anonymous function literals --- and
streams. Streams are an abstract layer to process data in a functional way, with `map',
`filter', `reduce' and more.
Java Streams are similar to the new built-in functions in this thesis:
\begin{listing}
\begin{javacode}
List<Integer> even = list.stream()
.filter(x -> x % 2 == 0)
.collect(Collectors.toList());
\end{javacode}
\begin{gocode}
even := filter(
func(x int) bool { return x%2 == 0 },
list)
\end{gocode}
\caption{Comparison Java Streams and functional Go}
\end{listing}
The lambda-syntax in Java is more concise than Go's function literals, where the
complete function header has to be provided\footnote{There is an open proposal
to add a lightweight anonymous function syntax to Go 2, which, if implemented,
would resolve this verbosity\autocite{go-lambdas}}.
However, the conversion to a stream and back to a list (with \mintinline{java}|list.stream()| and
\mintinline{java}|.collect(Collectors.toList())|)
is not required in Go, reducing the mental overhead for the programmer.
Apart from syntactical differences, Java Streams contain all the functions that
have been added as built-ins to Go, and a lot more.
On the other hand, Java's Syntax is arguably more complex than Go. An indicator for this might be
the language specification; Go's Language Specification is roughly 110 pages, while
Java's specification spans more than 700 pages\footnote{
The Java 8 Specification is 724\autocite{java-8-spec}, the Java 14
Specification 774\autocite{java-14-spec} pages.}, more than 6 times the size.
The consideration of which language to choose comes down to the experience with either language.
An experienced Java programmer will find it easier to start with Java's toolset, while programmers
coming from a C background may choose Go.

@ -0,0 +1,122 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
To learn functional programming without being introduced to a new syntax at the same time
ensures that programmers can fully concentrate on functional concepts. Although Go already
supported a functional programming style, the programmer may not have known if the code was
purely functional or if there still were imperative constructs embedded.
In the last chapters, functional purity has been defined as a law based on one simple rule: immutability.
Immutability dictates that once assigned, a variable's value never changes.
This in turn leads to function purity, which means that functions do not have side
effects and their return value is solely influenced by the function's parameters.
It has been shown that although purely functional languages like Haskell aim to be completely
pure, this objective is difficult to accomplish. The reason for this are Input / Output actions; user
input, network connections, randomness and time are all impure. Haskell wraps
these impure functions in the IO monad, which is a way to work around the compiler's optimisations
based on functional purity. In addition, although the IO monad does not make impure functions pure, it
does serve as documentation to its users (`if the function has IO, it is impure') and
guarantees a certain execution order.
Go on the other hand does not have this issue, as the Go compiler does not optimise execution
based on purity guarantees. Having a similar construct to the IO monad in Go would, as such,
only serve documentation purposes. Because of this, the decision has been taken to ignore
the impurity that is implied with IO actions.
Apart from IO, to achieve functional purity, the global state of a program should not influence
the return values of specific function. This ties into immutablitiy; if global state can
not be mutated, it can also not influence or change the result value of a function.
Based on these observations, a static code analysis tool has been developed that reports
all reassignments of variables. In other words, it forbids the usage of the regular
assignment operator (\mintinline{go}|=|), only allowing the short variable declarations
(\mintinline{go}|:=|). However, the experienced Go developer may know that the \mintinline{go}|:=|
operator can also reassign previously declared variables, implying that the solution to the
problem is not as simple as forbidding the assignment operator.
Further, there are many more edge cases that have been detected with careful testing:
To recursively call function literals, they must be declared beforehand (before assigning
the actual function to it) because of Go's scoping rules. Additionally, exceptions
had to be made for the blank identifier (\mintinline{go}|_|) and variables that are declared
outside of the current file.
With all of this in place, an algorithm has been chosen that is based on the identifier's
declaration position. In the \gls{ast} that is being checked, every identifier node has a field
which contains the position of it's declaration. If this does not match the current identifier's
position, the operation must be a reassignment.
The resulting binary, called `funcheck', successfully reports such reassignments:
\begin{gocode}
s := "hello world"
fmt.Println(s)
s = "and goodbye"
fmt.Println(s)
\end{gocode}
\begin{bashcode}
$> funcheck .
file.go:3:2: reassignment of s
\end{bashcode}
This linter can be used and executed against any Go package. To eliminate the reported errors,
code has to be rewritten in a purely functional manner.
However, functional code often relies heavily on lists and list-processing functions.
Although Go does not have a built-in list datatype, Go's slices, an abstraction built
on top of arrays,
mitigate a lot of downsides when comparing regular arrays to lists\footnote{Arrays / Slices
and Lists have a different runtime behaviour (indexing, adding or removing elements).
However, the performance of the code was not considered to be in scope for this thesis.}.
What Go's slices lack on the other hand are the typical higher-order functions like `map',
`filter' or `reduce'. These are commonly used in functional programming and most languages
contain implementations of these functions already --- Go does not.
Due to the lack of polymorphism, writing implementations for these functions
would result in a lot of duplicated code. To mitigate this issue, the most
common higher-order functions have been added to the list of Go's built-in functions,
which are registered, type-checked and implemented within the Go compiler.
As these are handled directly at compile time, built-in functions may be polymorphic, for
example allowing the programmer to use the same `filter' function for all list-types.
To determine which higher-order functions are most commonly used, the most popular
open-source Haskell projects (pandoc, shellcheck and purescript, to name a few) have
been analysed. As a result, `fmap', `fold', `filter' and `prepend'
(`cons') have been added as built-ins into the compiler.
These functions make it easier to write purely functional code in Go, in turn helping
the programmer to learn functional programming with a familiar language and syntax.
While implementing these functions in a regular Go program would be a matter of minutes,
adding them to the Go compiler is not as simple. To illustrate, the functions
have been written out in regular Go in the chapters~\ref{ch:impl-fmap} to~\ref{ch:impl-filter}
and are 33 lines of code, all functions combined. In the Go compiler, it is necessary to
register the functions, type-check the calls and manipulate the \gls{ast} instead of writing
the algorithm in Go code directly. This took more than 800 lines of code to do so.
As a result, using these functions is equal to using any other built-in function: there
is documentation in Godoc, type-checking support in the language server\footnote{If the
language server (gopls) is compiled against the modified version of Go, as
described in Appendix~\ref{appendix:build-gopls}}
and in the compilation phase, as well as a polymorphic function header, allowing the
programmer to call the function with any allowed type.
Demonstrations of these functions and how functional Go code looks like can be seen in
Chapter~\ref{ch:application}.
With these additions to Go and its ecosystem, aspiring functional programmers
can fully concentrate of the concepts of functional programming while keeping
a familiar syntax at hand. However, it should not be considered a fully featured
functional programming language. Rather, it should serve as a starting point and
make the transition to a language like Haskell easier.
Differences in the syntax between Haskell and Go exemplify why purely functional programming
languages have a distinct syntax compared to imperative or object-oriented languages.
Many constructs can be expressed more concisely in Haskell, without the additional
overhead that many programming languages, including Go, introduce.
Using `the right tool for the job' is important, and this paper shows that imperative or
object-oriented programming languages are not the right tool for production-grade
functional programming. However, they can serve as a good starting point and help transitioning
to a pure functional programming language.

@ -0,0 +1,85 @@
% -*- mode: latex; coding: utf-8; TeX-master: ../thesis -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
% !TEX root = ../thesis.tex
The aforementioned extensions to the Go language and its tooling should be a help to learn
functional programming. I believe that through these extensions it is easier to write
purely functional code in Go, enabling a developer to learn functional programming with
a familiar syntax in an obvious way. Here, Go's simplicity and verbosity are a key differentiator
to other languages. Instead of having as many features as possible to support every usecase,
Go has been designed with simplicity in mind\footnote{For example, Go only has 25 keywords, compared
to 37 in C99 and 84 in C++11}.
In many cases, this leads to more `verbose' code --- more lines of code compared to a similar
implementation in other languages. However, I argue that, especially for the first steps
in functional programming,
\begin{quote}
Clear is better than clever\autocite{cheney-clear}
\end{quote}
Staying in touch with this core Go principle, this results in functional code that may be
verbose, but easy to read and understand.
It should be clear that the result is not a `production-ready' functional programming language.
It is a language to help getting started with functional programming; either by re-implemeting pieces
of code that have not been clear in how they work, or by taking an imperative block of code
and refactoring it to make it purely functional.
In many cases, the resulting code will still look familiar to the imperative counterpart,
even if `funcheck' assures that it is purely functional. This, I believe, bridges the gap
that developers usually have to overcome by themselves.
To be a purely functional programming language, Go is missing too many features that would be
required to write concise functional code. The very basic type system\footnote{Not only
does Go not have polymorphism (yet), Go's type system is simple by design: there are no
implicit type conversions, no sum types (tagged unions, variant) and almost no type inference.
}, no advanced pattern matching and only explicit currying are all examples why Go is not useful
in day-to-day functional programming.
At the same time, the obvious nature of Go is exactly because it is missing all
of these features. The Go team explicitly tries not to include too many features within
the language in order to keep the complexity of code to a minimum\autocite{go-feature}.
The simplicity of the language is a key feature of Go and an important reason why it was
chosen to implement the ideas in the first place.
Especially for learning new concepts, hiding implementations and ideas behind features
may not be what is desired and helpful.
On another note, what has not been an aspect in this thesis is
performance. Go by itself is relatively performant, however functional constructs, for example
recursive function calls, come with a performance cost. While in purely functional languages
this can be optimised, Go cannot or does not want to do these optimisations\footnote{For example,
with tail call optimisation, the Go team explicitly decided not to do it because the stack trace
would be lost\autocite{go-tco-nope}}.
While the newly built-in functions do not have any low-hanging fruits in regards to optimisation,
they would benefit from more aggressive inlining\autocite{go-compiler-inline}, for example.
Benchmarking and optimising these functions was out of scope for this thesis, but may be tackled
in the future.
\newglossaryentry{sumtypes}{name=sum types,description={Sum types, often also called aggregated types,
variant or tagged union is a data structure that can hold one of several, predefined data types. For
example, Haskell's \mintinline{haskell}|Either| holds either a value of type A or type B. Similar to that,
\mintinline{haskell}|Maybe| can hold either a concrete value, or `Nothing'}}
The number one issue that still exists is the simple type system. Not only the lack of polymorphism, which
has been mitigated slightly by providing the most used higher-order functions as built-ins, but also the
lack of algebraic data types, especially \gls{sumtypes}.
Algebraic data types can be split up into two groups, product types and sum types.
Most product types can be built with Go too; records are basically
equal to structs, and tuples are not needed too often, as functions can just return multiple values.
Sum types however are not available in Go at all. It is possible to imitate sum types in Go
with interfaces (see the example code in Appendix~\ref{appendix:sum-types}), and ensure an
exhaustive match by a linter. This linter should have been implemented as part of this thesis.
However, after careful consideration, it has been decided that this will not be done
due to the simple reason that such a linter already exists\autocite{sushi-sumtypes}.
That linter could be merged with `funcheck', which is left as an exercise to the reader.
Further, a linter does not eliminate the fact that sum types are not properly integrated
into the language.
This may be an interesting area for further
research and implementation possibilities\footnote{There is a mention about sum types in the current
Go Generics Proposal\autocite{go-generics-proposal}, but the initial implementation of generics will
most likely not contain sum types}.

@ -0,0 +1,424 @@
\section{Information about this thesis}
This thesis, including this document, is contained in a single git repository
that can be found at GitHub\autocite{git-repo}.
All the work that has been done is open sourced under the Apache License 2.0,
except the Go source code, which has its own license.
To view the code, build or reproduce results, this git repository can be cloned
and its submodules checked out. The version that has been submitted can be checked
out through the tag `v1.0.0':
\begin{bashcode}
$> git clone https://github.com/tommyknows/bachelor-thesis.git
$> cd bachelor-thesis
$> git checkout v1.0.0
$> git submodule init
$> git submodule update
\end{bashcode}
The directory `thesis' contains the \LaTeX\ code for this paper. There is a helper
required for displaying code in the thesis which is located in `thesis/utils' and
needs to be built with `go build .'. However, a PDF which should be on the same state
as the source is provided in the repository too (`thesis/thesis.pdf').
The `work' directory contains code that has been developed in this thesis. In this
directory, the Go and funcheck source code can be found (see Appendix~\ref{appendix:install-fgo}
and~\ref{appendix:build-funcheck}). Further, some examples
of functional Go have been developed in the `example' directory. The `common-list-functions'
folder contains the script as mentioned in Appendix~\ref{appendix:function-occurrences}.
\section{Example for Functional Options}\label{appendix:funcopts}
This source code example demonstrates `functional options' as introduced in this paper.
Functional options are usually passed to a constructor to configure the new instance, in
this case a web server. The advantages of functional options are that the API ends up to
be cleaner and more easily extensible and allows the default use-case to be as simple
as possible.
\begin{code}
\gofile{../work/examples/functional-options/main.go}%
\caption{Functional Options for a simple web server}
\end{code}
\section{Analysis of function occurrences in Haskell code}\label{appendix:function-occurrences}
The results of the analysis have been acquired by running the `count-function' script
that is located in `work/common-list-functions' in the git repository\autocite{git-repo}.
The script utilises \href{https://github.com/BurntSushi/ripgrep}{ripgrep} to count the number of occurrences, so
this must be installed in order to run this script.
\begin{bashcode}
./count-function.sh ":" "((map)|(fmap))" "((foldr)|(foldl'?))" "filter" "reverse" "take" "drop" "sum" "zip" "product" "maximum" "min
imum"
Searching for occurrences in subdirectories of ./common-list-functions
Found 2912 occurrences of ":"
Found 1873 occurrences of "((map)|(fmap))"
Found 303 occurrences of "((foldr)|(foldl'?))"
Found 262 occurrences of "filter"
Found 154 occurrences of "reverse"
Found 108 occurrences of "take"
Found 81 occurrences of "drop"
Found 44 occurrences of "sum"
Found 38 occurrences of "zip"
Found 15 occurrences of "product"
Found 45 occurrences of "maximum"
Found 10 occurrences of "minimum"
\end{bashcode}
The terms are searched with a leading and trailing space to get exact matches. Further, as can be seen in
the call to the script, the search combines the results of map together with fmap, and foldr with foldl
and foldl'.
\section{Mutating variables in Go}\label{appendix:mutation}
Source Code~\ref{code:mutation} shows how pointers are used to mutate data in Go. This does
not necessarily need to be a `struct' type, pointers can be used of any type.
Pointers have to be used to modify values because Go is a copy-by-value language and thus
copies the parameters that are passed to a function.
\begin{code}
\gofile{../work/examples/mutate/main.go}%
\caption{Example on how to mutate data in Go}\label{code:mutation}
\end{code}
\section{Shadowing variables in Go}\label{appendix:shadowing}
Source Code~\ref{code:shadowing} demonstrates the block scoping and shadowing rules
in Go.
\begin{code}
\gofile{../work/examples/shadowing/main.go}%
\caption{Example on how shadowing works on block scopes}\label{code:shadowing}
\end{code}
\section{Foldl and Foldl' difference}\label{appendix:foldl-strictness}
This code example shows the difference between foldl and foldl' in their
execution. What can be seen is that foldl builds up a call stack, while
foldl' executes the calls during the traversal.
\begin{code}
\begin{haskellcode}
> (?) :: Int -> Int -> Int
> _ ? 0 = 0
> x ? y = x*y
>
> list :: [Int]
> list = [2,3,undefined,5,0]
>
> foldl (?) 1 list
foldl (?) 1 [2,3,undefined,5,0] -->
foldl (?) (1 ? 2) [3,undefined,5,0] -->
foldl (?) ((1 ? 2) ? 3) [undefined,5,0] -->
foldl (?) (((1 ? 2) ? 3) ? undefined) [5,0] -->
foldl (?) ((((1 ? 2) ? 3) ? undefined) ? 5) [0] -->
foldl (?) (((((1 ? 2) ? 3) ? undefined) ? 5) ? 0) [] -->
((((1 ? 2) ? 3) ? undefined) ? 5) ? 0 -->
0
> foldl' (?) 1 list
foldl' (?) 1 [2,3,undefined,5,0] -->
1 ? 2 --> 2
foldl' (?) 2 [3,undefined,5,0] -->
2 ? 3 --> 6
foldl' (?) 6 [undefined,5,0] -->
6 ? undefined -->
*** Exception: Prelude.undefined
\end{haskellcode}
\caption{foldl and foldl' strictness\autocite{fold-types}}
\end{code}
\section{Workaround for the missing foldl implementation in Go}\label{appendix:foldl-go}
This code block exemplifies how foldl could be implemented in Go code. It is based on the example
from Appendix~\ref{appendix:foldl-strictness}, rewritten in Go. While Go does not know about
the concept of laziness, the programmer may implement the laziness himself by working with function
closures.
In this example, \mintinline{go}|*int| is used instead of \mintinline{go}|int| to simulate Haskell's
\mintinline{haskell}|undefined| with a nil-pointer.
If a nil-pointer is dereferenced, the program will panic.
In the lazy version of this code (utilising `myFold' and `mulLazy'), the panic does not occur because
the nil-pointer is never dereferenced as the function closure is never executed. This is equal
to the `foldl' demonstration in Appendix~\ref{appendix:foldl-strictness}.
The non-lazy version (`foldl' and `mul') executes the function while traversing the slice and thus panics.
\begin{code}
\gofile{../work/examples/foldl-workaround/main.go}%
\begin{bashcode}
$> fgo run .
0
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x109e945]
goroutine 1 [running]:
...
\end{bashcode}
\caption{Working around the missing foldl implementation in Go\label{code:foldl-go}}
\end{code}
\section{Prettyprint implementation}\label{appendix:prettyprint-func}
These code blocks show the same package `prettyprint', once in idiomatic Go and once
in functional Go. What can be seen is that the \mintinline{go}|for| loops have been replaced
by the usage of `foldl' and anonymous functions.
\begin{code}
\gofile{../work/funcheck/prettyprint/prettyprint.go}%
\caption{The original prettyprint implementation\autocite{prettyprint-orig}}
\end{code}
\begin{code}
\begin{gocode}
package prettyprint
import (
"bytes"
"fmt"
"go/ast"
"go/printer"
"go/token"
"golang.org/x/tools/go/analysis"
)
var Analyzer = &analysis.Analyzer{
Name: "prettyprint",
Doc: "prints positions",
Run: run,
}
type null struct{}
func checkDecl(as *ast.DeclStmt, fset *token.FileSet) {
fmt.Printf("Declaration %q: %v\n", render(fset, as), as.Pos())
check := func(_ null, spec ast.Spec) (n null) {
val, ok := spec.(*ast.ValueSpec)
if !ok {
return
}
if val.Values != nil {
return
}
if _, ok := val.Type.(*ast.FuncType); !ok {
return
}
fmt.Printf("\tIdent %q: %v\n", render(fset, val), val.Names[0].Pos())
return
}
if decl, ok := as.Decl.(*ast.GenDecl); ok {
_ = foldl(check, null{}, decl.Specs)
}
}
func checkAssign(as *ast.AssignStmt, fset *token.FileSet) {
fmt.Printf("Assignment %q: %v\n", render(fset, as), as.Pos())
check := func(_ null, expr ast.Expr) (n null) {
ident, ok := expr.(*ast.Ident) // Lhs always is an "IdentifierList"
if !ok {
return
}
fmt.Printf("\tIdent %q: %v\n", ident.String(), ident.Pos())
switch {
case ident.Name == "_":
fmt.Printf("\t\tBlank Identifier!\n")
case ident.Obj == nil:
fmt.Printf("\t\tDecl is not in the same file!\n")
default:
// make sure the declaration has a Pos func and get it
declPos := ident.Obj.Decl.(ast.Node).Pos()
fmt.Printf("\t\tDecl %q: %v\n", render(fset, ident.Obj.Decl), declPos)
}
return
}
_ = foldl(check, null{}, as.Lhs)
}
func run(pass *analysis.Pass) (interface{}, error) {
inspect := func(_ null, file *ast.File) (n null) {
ast.Inspect(file, func(n ast.Node) bool {
switch as := n.(type) {
case *ast.DeclStmt:
checkDecl(as, pass.Fset)
case *ast.AssignStmt:
checkAssign(as, pass.Fset)
}
return true
})
return
}
_ = foldl(inspect, null{}, pass.Files)
return nil, nil
}
// render returns the pretty-print of the given node
func render(fset *token.FileSet, x interface{}) string {
var buf bytes.Buffer
if err := printer.Fprint(&buf, fset, x); err != nil {
panic(err)
}
return buf.String()
}
\end{gocode}
\caption{The refactored, functional prettyprint implementation\autocite{prettyprint-functional}}
\end{code}
\section{Imitating Sum types in Go}\label{appendix:sum-types}
\begin{code}
\gofile{../work/examples/sumtypes/main.go}%
\caption{Demonstration of how sum types can be imitated with interfaces}
\end{code}
\section{Compiling and using functional Go}\label{appendix:install-fgo}
To compile and use the changes to the Go compiler that have been implemented in
this thesis, these instructions should be followed.
First, check out the Go source code:
\begin{bashcode}
$> git clone https://github.com/tommyknows/go.git && cd go
$> git checkout bachelor-thesis
\end{bashcode}
\subsection{With Docker}
If Docker is installed on your system, you can follow these steps from within
the checked out `go' git repository on the branch `bachelor-thesis'.
The downside of this approach is that it complicates building and sharing binaries.
To compile your own project, the directory has to be mounted into the container.
If your Guest OS is not Linux, cross-compilation is required so that the executable
can be ran on the host.
These steps have been wrapped inside a script that prints out the necessary commands
to configure your environment.
\begin{bashcode}
$> eval "$(./setup-docker.sh)"
\end{bashcode}
The commands within the shell script will
build Go in the container and print commands to configure the environment. The `eval'
command then executes these printed commands. Executing this command may take a while,
as the Go compiler is compiled within this process.
To build projects with the functional Go installation, simply use `fgo' on the command line.
An alias has been created that mounts the current directory and executes the `fgo'
command within the container.
Note that if this only configures the `fgo' command in the current shell session. To
persist it across shell-sessions, execute the script without eval:
\begin{bashcode}
$> ./setup-docker.sh
\end{bashcode}
And add the printed commands to your `.bashrc' (or equivalent). Further, you may
also need to change the binary path from `/tmp/fgo/bin' to a path which is not
cleaned up regularly.
\subsection{With a working Go installation}
If you already have a working Go installation on your system, the following
steps provide a way to get functional Go up and running in the same way
a normal go installation does.
These steps need to be executed from within the checked out `go' git
repository on the branch `bachelor-thesis'.
Build the functional Go binary and configure the environment:
\begin{bashcode}
$> cd ./src
$> ./make.bash
$> ln -s $(realpath $(pwd)/../bin/go) /usr/local/bin/fgo
$> go env -w GOROOT=$(realpath $(pwd)/..)
\end{bashcode}
The `go env' command sets the GOROOT to point to the newly compiled tools
and source code and is valid for the current shell session only.
\subsection{Using the installation}
After these steps, the binary (or alias) `fgo' can be used to test and build
functional Go code. `fgo' is not different to the normal `go' command, so
all commands that work with the normal `go' command also work with
the `fgo' command.
\begin{bashcode}
$> cd <code directory>
$> fgo test ./...
$> fgo build ./...
\end{bashcode}
\section{Building Funcheck}\label{appendix:build-funcheck}
Funcheck needs to be built against functional Go to properly detect the builtin functions.
If you have not done so already, install `fgo' as shown in Appendix~\ref{appendix:install-fgo}.
Then, funcheck can be installed directly with `go get' (or rather, `fgo get'). `go get'
downloads the source code to the Go modules directory (usually in \mintinline{bash}|$GOPATH/pkg/mod|),
compiles the specified package and moves the binary to \mintinline{bash}|$GOPATH/bin|.
\begin{bashcode}
$> # go get should not be called from within a go module
$> cd /tmp
$> fgo get github.com/tommyknows/funcheck
$> funcheck -h
\end{bashcode}
This installs `funcheck' into \mintinline{bash}|$GOBIN| or, if \mintinline{bash}|$GOBIN|
is not set, into \mintinline{bash}|$GOPATH/bin|.
You can also clone the git repository and use `fgo build' to build `funcheck':
\begin{bashcode}
$> git clone https://github.com/tommyknows/funcheck.git
$> cd funcheck
$> fgo build .
$> mv ./funcheck /usr/local/bin/funcheck
$> funcheck -h
\end{bashcode}
To run funcheck against the current directory / package, simply run
\begin{bashcode}
$> funcheck .
\end{bashcode}
\section{Building Gopls}\label{appendix:build-gopls}
Gopls is the official language server for Go. Similar to funcheck, there are two options
to install it on your local machine.
Installing with `go get':
\begin{bashcode}
$> # go get should not be called from within a go module
$> cd /tmp
$> fgo get golang.org/x/tools/gopls
$> gopls -h
\end{bashcode}
Or by downloading the source manually:
\begin{bashcode}
$> git clone https://github.com/golang/tools.git
$> cd ./tools/gopls
$> fgo build .
$> mv ./gopls /usr/local/bin/gopls
$> gopls -h
\end{bashcode}
% generate a chapter without the chapter heading
\clearpage
\phantomsection
\addtocounter{section}{1}
\addcontentsline{toc}{section}{%
\protect\numberline{\thesection}%
Assignment}
\includepdf[pages=-]{assignment.pdf}

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -0,0 +1,46 @@
introduction:
- Functional Programming Hype
- Haskell => functional par excellence:
- examples
- learning curve extremely steep, both for syntax & paradigm
- Conclusion; Easier, more familiar (& verbose) introduction to FP needed:
- should not be "productive", but easy to learn FP
- Cleary state the goal; Educational language
- Why choose Go:
- Easy & familiar syntax (C)
- GC (Rust too complicated, though more powerful TS for FP)
- Existing Work:
- Talk by Francesc @ GopherCon; functional Go
- Downsides of Go:
- type system (polymorphism, sum types)
- no Lists
- no FP enforcement
- Examples to everything, possibly comparison to Haskell?
- TCO / benchmarking?
- Work to be done / mitigation:
- Powerful list implementation (polymorphic, supported by compiler) (Syntax TBD)
- FuncCheck (Rules TBD)
related_work:
- ???
-------- DONE --------
methodology:
- list functions implementation:
- plan, benchmarks, constraints & limitations, goal
- which functions:
- map (name? fmap?)
- prepend (similar to append, but way more expensive :-) )
- filter
- reduce
- zip
- funccheck:
- research "rules" for FP
- compare them
- create a curated list of rules
- implement those in a linter
- inspect results
application:
- ???
experiments_and_results:
- ???
discussion:
- ???

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

@ -0,0 +1,6 @@
- Cite Wikipedia?
- Personal statements & opinions? (clearly marked)
- citation for things like "these features are also what makes Haskell famously hard to learn."
- cite Blog posts? (e.g. stackoverflow.blog)
- BA rights?
- should or will?

@ -0,0 +1,947 @@
@ONLINE{python-popularity,
title = "The incredible growth of Pyhon",
url = "https://stackoverflow.blog/2017/09/06/incredible-growth-python/?_ga=2.199625454.1908037254.1532442133-221121599.1532442133",
year = 2017,
month = Sep,
day = 06,
urldate="2020-02-27",
author = {David Robinson},
}
@TECHREPORT{rust-loved,
title = "Stack Overflow Developer Survey 2019",
institution = "Stack Overflow",
year=2019,
url = "https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted",
urldate="2020-02-27",
}
@ONLINE{rust-functional,
title = "Functional Language Features",
url = "https://doc.rust-lang.org/book/ch13-00-functional-features.html",
author = {Steve Klabnik and Carol Nichols and Rust Community},
year=2018,
}
@ONLINE{quora-funcprog,
title = "Why should I learn a functional programming language",
url = {https://www.quora.com/Why-should-I-learn-a-functional-programming-language},
author = {Tikhon Jelvis},
year= 2014,
urldate = "2020-05-22",
}
@ONLINE{blog1-funcprog,
title = "Why Everyone Should Learn Functional Programming Today",
url = {https://medium.com/better-programming/why-everyone-should-learn-functional-programming-today-c96a5b10d27d},
year = 2019,
month = Nov,
day = 25,
author = {Robert Quinlivan},
urldate = "2020-05-22",
}
@ONLINE{blog2-funcprog,
title = "Why Functional Programming",
author = {Eric Normand},
year = 2019,
month = Jul,
day = 01,
urldate = "2020-05-22",
url = {https://purelyfunctional.tv/article/why-functional-programming/},
}
@ONLINE{blog3-funcprog,
title = "Why you should learn Functional Programming",
author = {Anssi Piirainen},
year = 2020,
month = Jan,
day = 13,
urldate = "2020-05-22",
url = {https://dev.to/anssip/why-you-should-learn-functional-programming-3h2g},
}
@ONLINE{blog4-funcprog,
title = "You SHould Learn Functional Programming in 2018",
author = {Allan MacGregor},
year = 2018,
month = Jun,
day = 04,
urldate = "2020-05-22",
url = {https://dev.to/allanmacgregor/you-should-learn-functional-programming-in-2018-4nff},
}
@ARTICLE{functional-controversy,
title="What is a purely functional language?",
volume={8},
DOI={10.1017/S0956796897002943},
number={1},
journal={Journal of Functional Programming},
publisher={Cambridge University Press},
author={Amr Sabry},
year={1998},
pages={122},
}
@ONLINE{haskell-quicksort,
author = {{HaskellWiki contributors}},
title = "Introduction --- HaskellWiki{,} ",
url = "https://wiki.haskell.org/index.php?title=Introduction&oldid=63206",
year = 2020,
month = Feb,
day = 29,
urldate = "2020-03-01",
}
@ONLINE{golang-publish,
title= {{Google's Go: A New Programming Language That's Python Meets C++}},
author = {Jason Kincaid},
year = 2009,
month = Nov,
url = "https://techcrunch.com/2009/11/10/google-go-language/",
institution = "TechCrunch",
urldate = "2020-02-29",
}
@ONLINE{golang-slices,
title = {{Go Slices: usage and internals}},
author = {Andrew Gerrand},
year = 2011,
month = Jan,
day = 05,
url = {https://blog.golang.org/go-slices-usage-and-internals},
urldate = "2020-02-29",
}
@ONLINE{go-basetypes,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Boolean_types},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-03-02",
}
@ONLINE{go-spec,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-03-02",
}
@ONLINE{comparison-functional-languages,
title = {{Comparison of functional programming languages}},
author = {{Wikipedia contributors}},
urldate = "2020-03-04",
year = 2020,
month = Feb,
day = 07,
url = {https://en.wikipedia.org/w/index.php?title=Comparison_of_functional_programming_languages&oldid=939648685},
}
@TECHREPORT{tiobe-index,
title = {{TIOBE Index for May 2020}},
urldate = "2020-05-22",
institution = "TIOBE",
year = 2020,
month = May,
url = {https://www.tiobe.com/tiobe-index/},
}
@ONLINE{why-lists,
title = {{Why are lists so heavily used in most, if not all, functional programming languages?}},
urldate = "2020-05-22",
year = 2014,
month = Sep,
day = 08,
url = {https://www.quora.com/Why-are-lists-so-heavily-used-in-most-if-not-all-functional-programming-languages?share=1},
author = {Tikhon Jelvis},
}
@ONLINE{haskell-hard-one,
title = {{Why is Haskell so hard to learn?}},
author = {{n/a}},
url = {https://www.quora.com/Why-is-Haskell-so-hard-to-learn},
year = 2017,
month = Jun,
day = 29,
urldate = "2020-03-04",
}
@ONLINE{haskell-hard-two,
title = {{A lazy evaluation}},
url = {http://connolly.io/posts/lazy-evaluation/},
year = 2014,
month = Feb,
day = 07,
urldate = "2020-03-04",
author = {Ian Connolly},
}
@ONLINE{haskell-hard-three,
title = {{Haskell's steep learning curve}},
url = {https://www.quora.com/How-much-of-Haskells-steep-learning-curve-is-related-to-the-number-of-terms-one-has-to-memorize?share=1},
author = {{n/a}},
year = 2018,
month = 10,
day = 23,
urldate = "2020-03-04",
}
@ONLINE{haskell-hard-four,
year = 2007,
month = Sep,
day = 12,
urldate = "2020-03-04",
author = {{HaskellWiki contributors}},
title = "Humor/LearningCurve --- HaskellWiki{,} ",
url = "https://wiki.haskell.org/index.php?title=Humor/LearningCurve&oldid=15543",
}
@ONLINE{slice-tricks,
title = {{SliceTricks}},
url = {https://github.com/golang/go/wiki/SliceTricks/a87dff31b0d8ae8f26902b0d2dbe7e4e77c7e6e3},
organization = {Github},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 15,
urldate = "2020-03-04",
}
@ONLINE{haskell-list-funcs,
url = {https://wiki.haskell.org/index.php?title=How_to_work_on_lists&oldid=63130},
year = 2019,
month = 11,
day = 15,
urldate = "2020-03-04",
author = {{HaskellWiki contributors}},
title = "How to work on lists --- HaskellWiki{,} ",
}
@ONLINE{go-http-doc,
title = {{http package - go.dev}},
url = {https://pkg.go.dev/net/http@go1.14?tab=doc#example-HandleFunc},
author = {{The Go Authors}},
year = 2020,
month = Feb,
day = 25,
urldate = "2020-03-06",
}
@ONLINE{functional-options,
title = {{Functional options for friendly APIs}},
url = {https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis},
author = {Dave Cheney},
year = 2014,
month = Oct,
day = 17,
urldate = "2020-03-06",
}
@ONLINE{cheney-clear,
title = {{Clear is better than clever}},
url = {https://dave.cheney.net/2019/07/09/clear-is-better-than-clever},
author = {Dave Cheney},
year = 2019,
month = Jul,
day = 09,
urldate = "2020-05-21",
}
@ONLINE{go-ternary,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#Does_Go_have_a_ternary_form},
author = {{The Go Authors}},
urldate = "2020-05-21",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{csharp-functional,
title = {{The history of C\# - C\# guide}},
url = {https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-30},
author = {Erik Dietrich and Patrick Smacchia},
urldate = "2020-06-05",
year = 2020,
month = Apr,
day = 04,
}
@ONLINE{go-pointerarithmetic,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#no_pointer_arithmetic},
author = {{The Go Authors}},
urldate = "2020-06-05",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{go-feature,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#Why_doesnt_Go_have_feature_X},
author = {{The Go Authors}},
urldate = "2020-05-21",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{func-go-talk,
title = {{Functional Go?}},
organization = {Youtube},
author = {Francesc Campoy Flores},
url = {https://www.youtube.com/watch?v=ouyHp2nJl0I},
year = "2015",
month = Dec,
day = 11,
urldate = "2020-03-06",
}
@ONLINE{go-tco,
title = {{proposal: Go 2: add become statement to support tail calls}},
organization = {Github},
url = {https://github.com/golang/go/issues/22624},
author = {Ian Lance Taylor},
year = 2017,
month = Nov,
day = 07,
urldate = "2020-03-06",
}
@ONLINE{go-tco-nope,
title = {{Tail call optimization - google groups}},
url = {https://groups.google.com/d/msg/golang-nuts/nOS2FEiIAaM/miAg83qEn-AJ},
author = {Russ Cox},
year = 2011,
month = Feb,
day = 13,
urldate = "2020-06-05"
}
@ONLINE{go-functional,
title = {{go-functional/core}},
author = {Aaron Schlesinger},
organization = {Github},
url = {https://github.com/go-functional/core/tree/700b20aec09da808a67cc29ae2c54ad64f842851},
year = 2019,
month = Nov,
day = 07,
urldate = "2020-03-06",
}
@ONLINE{go-functional-readme,
title = {{go-functional/core}},
author = {Aaron Schlesinger},
organization = {Github},
url = {https://github.com/go-functional/core/blob/700b20aec09da808a67cc29ae2c54ad64f842851/README.md},
year = 2019,
month = Nov,
day = 07,
urldate = "2020-03-06",
}
@ONLINE{github-shellcheck,
title = {{koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts}},
date = 2020,
organization = {Github},
author = {Vidar Holen and contributors},
url = {https://github.com/koalaman/shellcheck/tree/68a03e05e5e030d7274c712ffa39768310e70f8a},
year = 2020,
month = Mar,
day = 08,
urldate = "2020-03-12",
}
@ONLINE{github-pandoc,
title = {{jgm/pandoc: Universal Markup Converter}},
organization = {Github},
author = {John MacFarlane},
url = {https://github.com/jgm/pandoc/tree/91f2bcfe73fa3a489654ee74bca02e24423dc5c0},
urldate = "2020-03-12",
year = 2020,
month = Mar,
day = 10,
}
@ONLINE{github-postgrest,
title = {{PostgREST/postgrest: REST API for any Postgres database}},
organization = {Github},
author = {{The PostgREST contributors}},
url = {https://github.com/PostgREST/postgrest/tree/dea57bd1bec9ba5c4e438de80b2017eee4a30a40},
year = 2020,
month = Mar,
day = 07,
urldate = "2020-03-12",
}
@ONLINE{github-semantic,
title = {{github/semantic: Parsing, analyzing, and comparing source code across many languages}},
organization = {Github},
author = {{Github and contributors}},
url = {https://github.com/github/semantic/tree/124b45d36d7f81e45a9aa3aef588fd5e132fb6fd},
year = 2020,
month = Mar,
day = 11,
urldate = "2020-03-12",
}
@ONLINE{github-purescript,
title = {{purescript/purescript: A strongly-typed language that compiles to JavaScript}},
organization = {Github},
url = {https://github.com/purescript/purescript/tree/183fc22549011804d973e01654e354b728f2bc70},
author = {{The PureScript contributors}},
year = 2020,
month = Mar,
day = 11,
urldate="2020-03-12",
}
@ONLINE{github-elmcompiler,
title = {{elm/compiler: Compiler for Elm, a functional language for reliable webapps}},
organization = {Github},
author = {{The Elm Authors}},
url = {https://github.com/elm/compiler/tree/66c72f095e6da255bde8df6a913815a7dde25665},
year = 2020,
month = Mar,
day = 11,
urldate = "2020-03-12",
}
@ONLINE{github-haxl,
title = {{facebook/haxl: A Haskell library that simplifies access to remote data, such as databases or web-based services}},
organization = {Github},
author = {{Github and contributors}},
url = {https://github.com/facebook/Haxl/tree/0009512345fbd95fe1c745414fffed6c63ccd1aa},
year = 2020,
month = Mar,
day = 03,
urldate = "2020-03-12",
}
@ONLINE{git-repo,
title = {{tommyknows/bachelor-thesis}},
date = 2020,
organization = {Github},
url = {https://github.com/tommyknows/bachelor-thesis},
author = {Ramon Rüttimann},
urldate = "2020-03-13",
}
@ONLINE{github-popular-haskell,
title = {{Search - stars:>1000 language:Haskell}},
date = 2020,
month = Mar,
organization = {Github},
author = {{n/a}},
url = {https://github.com/search?l=&o=desc&q=stars%3A%3E1000+language%3AHaskell&s=stars&type=Repositories},
urldate = "2020-03-12",
}
@ONLINE{godoc,
title = {{Godoc: documenting Go code}},
year = 2011,
month = Mar,
day = 31,
author = {Andrew Gerrand},
url = {https://blog.golang.org/godoc-documenting-go-code},
urldate = "2020-03-13",
}
@ONLINE{godoc-builtin,
title = {{builtin package - go.dev}},
year = 2020,
month = Mar,
day = 25,
url = {https://pkg.go.dev/builtin@go1.14?tab=doc},
author = {{The Go Authors}},
urldate = "2020-03-13",
}
@ONLINE{builtin-impl,
title = {{go/builtin.go at go1.14 - golang/go}},
year = 2019,
month = Apr,
day = 05,
organization = {Github},
url = {https://github.com/golang/go/blob/go1.14/src/builtin/builtin.go},
author = {{The Go Authors}},
urldate = "2020-03-13",
}
@ONLINE{ast-node-dag,
title = {{go/syntax.go at go1.14 - golang/go}},
year = 2019,
month = Nov,
day = 12,
organization = {Github},
url = {https://github.com/golang/go/blob/go1.14/src/cmd/compile/internal/gc/syntax.go#L18},
author = {{The Go Authors}},
urldate = "2020-03-20",
}
@ONLINE{gopls,
title = {{gopls documentation}},
year = 2019,
month = 12,
day = 17,
organization = {Github},
url = {https://github.com/golang/tools/blob/0b43622770f0bce9eb6c5d0539003ebbc68b9c70/gopls/README.md},
author = {{The Go Authors}},
urldate = "2020-03-20",
}
@ONLINE{ba-go1-14-thesis-diff,
title = {{Comparing go1.14...bachelor-thesis - tommyknows/go}},
url = {https://github.com/tommyknows/go/compare/go1.14...tommyknows:bachelor-thesis},
organization = {Github},
author = {Ramon Rüttimann},
urldate = "2020-06-11",
year = 2020,
month = May,
day = 30,
}
@ONLINE{sushi-sumtypes,
title = {{BurntSushi/go-sumtype}},
year = 2019,
month = Mar,
day = 04,
author = {Andrew Gallant and contributors},
url = {https://github.com/BurntSushi/go-sumtype/tree/fcb4a6205bdc6ce526f359ae5eae5fb6ded53916},
organization = {Github},
urldate = "2020-05-30",
}
@ONLINE{internal-packages,
title = {{Go 1.4 "Internal" Packages}},
year = 2014,
month = Jun,
url = {https://docs.google.com/document/d/1e8kOo3r51b2BWtTs_1uADIA5djfXhPT36s6eHVRIvaU/edit},
urldate = "2020-04-01",
author = {Russ Cox},
}
@ONLINE{fold-types,
month = Mar,
day = 29,
url = {https://wiki.haskell.org/index.php?title=Foldr_Foldl_Foldl%27&oldid=62842},
urldate = "2020-04-07",
author = {{HaskellWiki contributors}},
title = "Foldr Foldl Foldl' --- HaskellWiki{,} ",
year = "2019",
}
@ONLINE{less-is-more,
title = {{Less is exponentially more}},
year = 2012,
month = Jun,
day = 25,
author = {Rob Pike},
url = {https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html},
urldate = "2020-04-10",
}
@ONLINE{nuts-compiler,
title = "Why does Go programs compile faster than Java or C\#?",
year = 2014,
month = Mar,
day = 25,
author = {Rob Pike},
url = {https://groups.google.com/d/msg/golang-nuts/al4iuFXLPeA/PYNcUQ0_uAEJ},
urldate = "2020-04-10",
}
@ONLINE{go-faq,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#creating_a_new_language},
author = {{The Go Authors}},
urldate = "2020-04-10",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{go-faq-symbol,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#different_syntax},
author = {{The Go Authors}},
urldate = "2020-04-10",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{go-interface-slice-conv,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#convert_slice_with_same_underlying_type},
author = {{The Go Authors}},
urldate = "2020-05-26",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{go-interface-slice-conv2,
title = {{Frequently Asked Questions}},
url = {https://golang.org/doc/faq#convert_slice_of_interface},
author = {{The Go Authors}},
urldate = "2020-05-26",
year = 2019,
month = Sep,
day = 18,
}
@ONLINE{compiler-readme,
title = {{Introduction to the Go compiler}},
url = {https://github.com/golang/go/blob/go1.14/src/cmd/compile/README.md},
organization = {Github},
author = {{The Go Authors}},
year = 2018,
month = Jul,
day = 04,
urldate = "2020-04-10",
}
@ONLINE{go-spec-builtins,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Built-in_functions},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-04-10",
}
@ONLINE{empty-interface,
title = {{Go Proverbs - Rob Pike - Gopherfest - November 18, 2015}},
organization = {Youtube},
author = {Rob Pike},
url = {https://www.youtube.com/watch?v=PAAkCSZUG1c&t=7m36s},
year = "2015",
month = Nov,
day = 18,
urldate = "2020-04-10",
}
@ONLINE{haskell-map,
title = {{Haskell : map}},
author = {Miloslav Nic},
year = {n/d},
url = {http://zvon.org/other/haskell/Outputprelude/map_f.html},
urldate = "2020-04-10",
}
@ONLINE{functor-wiki,
title = {{Functor}},
author = {{HaskellWiki contributors}},
url = {https://wiki.haskell.org/index.php?title=Functor&oldid=63127},
year = 2019,
month = Nov,
day = 10,
urldate="2020-04-10",
}
@ONLINE{fmt-godoc,
title = {{fmt package - go.dev }},
url = {https://pkg.go.dev/fmt@go1.14?tab=doc},
author = {{The Go Authors}},
year = 2020,
month = Feb,
day = 25,
urldate="2020-04-12",
}
@ONLINE{cons-image-source,
title = {{common-lisp - Sketching cons cells | common lisp Tutorial}},
url = {https://riptutorial.com/common-lisp/example/17740/sketching-cons-cells},
author = {{n/a}},
year = {n/d},
urldate = "2020-04-12",
}
@ONLINE{spec-identifiers,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Identifiers},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-04-12",
}
@ONLINE{fmap-walk-implementation,
title = {{go/walk.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-06-11",
url = "https://github.com/tommyknows/go/blob/bachelor-thesis/src/cmd/compile/internal/gc/walk.go#L3055",
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{go-compiler-inline,
title = {{cmd/compile: improve inlining cost model}},
year = 2016,
month = Oct,
day = 24,
url = {https://github.com/golang/go/issues/17566},
organization = {Github},
author = {Josh Bleecher Snyder},
}
@ONLINE{new-builtins-universe,
title = {{go/universe.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = Apr,
day = 19,
urldate = "2020-06-07",
url = {https://github.com/tommyknows/go/blob/bachelor-thesis/src/go/types/universe.go#L110},
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{funcheck-ast-types,
title = {{funcheck/assigncheck.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-06-07",
url = {https://github.com/tommyknows/funcheck/blob/bachelor-thesis/assigncheck/assigncheck.go#L33},
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{new-builtins-godoc,
title = {{go/builtin.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-06-07",
url = "https://github.com/tommyknows/go/blob/bachelor-thesis/src/builtin/builtin.go#L142",
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{prepend-walk-implementation,
title = {{go/walk.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-05-31",
url = "https://github.com/tommyknows/go/blob/bachelor-thesis/src/cmd/compile/internal/gc/walk.go#L3011",
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{fold-walk-implementation,
title = {{go/walk.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-05-31",
url = "https://github.com/tommyknows/go/blob/bachelor-thesis/src/cmd/compile/internal/gc/walk.go#L3132",
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{filter-walk-implementation,
title = {{go/walk.go at bachelor-thesis - tommyknows/go}},
year = 2020,
month = May,
day = 30,
urldate = "2020-05-31",
url = "https://github.com/tommyknows/go/blob/bachelor-thesis/src/cmd/compile/internal/gc/walk.go#L3196",
organization = {Github},
author = {Ramon Rüttimann},
}
@ONLINE{golangci-lint,
title = {{golangci/golangci-lint - Linters runner for Go}},
year = 2020,
month = Mar,
day = 15,
urldate = "2020-04-18",
url = {https://github.com/golangci/golangci-lint/commit/4958e50dfe8c95bebab5eaf360a3bc1fdc9574fe},
organization = {Github},
author = {{The golangci-lint contributors}},
}
@ONLINE{functional-purity-wiki,
author = {{Wikipedia contributors}},
title = "Purely functional programming --- {Wikipedia}{,} The Free Encyclopedia",
year = "2019",
url = "https://en.wikipedia.org/w/index.php?title=Purely_functional_programming&oldid=910398359",
urldate = "2020-04-18",
month = Aug,
day = 11,
}
@ONLINE{haskell-io,
author = {{HaskellWiki contributors}},
title = "IO inside --- HaskellWiki{,} ",
year = "2020",
month = Mar,
day = 08,
url = "https://wiki.haskell.org/index.php?title=IO_inside&oldid=63262",
urldate = "2020-04-26"
}
@ONLINE{short-hand-decl,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Short_variable_declarations},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-05-03",
}
@ONLINE{spec-operators,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Operators_and_punctuation},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-05-03",
}
@ONLINE{spec-scope,
title = {{The Go Programming Language Specification}},
url = {https://golang.org/ref/spec#Declarations_and_scope},
author = {{The Go Authors}},
year = 2020,
month = Jan,
day = 14,
urldate = "2020-05-08",
}
@ONLINE{funcheck-examples,
title = {{funcheck/example.go at master - tommyknows/funcheck}},
year = 2020,
month = May,
day = 30,
url = {https://github.com/tommyknows/funcheck/blob/master/assigncheck/testdata/example.go},
organization = {Github},
author = {Ramon Rüttimann},
urldate = "2020-06-11",
}
@ONLINE{go-analysis,
title = {{analysis package - go.dev}},
year = 2020,
month = May,
day = 09,
url = {https://pkg.go.dev/golang.org/x/tools@v0.0.0-20200509030707-2212a7e161a5/go/analysis?tab=doc},
author = {{The Go Authors}},
urldate = "2020-05-09",
}
@ONLINE{go-ast-object,
title = {{go/scope.go at go1.14 - golang/go}},
year = 2017,
month = Jan,
day = 19,
url = {https://github.com/golang/go/blob/go1.14/src/go/ast/scope.go#L64},
organization = {Github},
author = {{The Go Authors}},
urldate = "2020-05-10",
}
@ONLINE{ast-positions,
title = {{prettyprint package - go.dev}},
year = 2020,
month = May,
day = 31,
url = {https://pkg.go.dev/github.com/tommyknows/funcheck@v0.1.2/prettyprint?tab=doc},
organization = {Github},
author = {Ramon Rüttimann},
urldate = "2020-05-31",
}
@ONLINE{prettyprint-functional,
title = {{funcheck/prettyprint.go at c15f4ec - tommyknows/funcheck}},
year = 2020,
month = May,
day = 13,
url = {https://github.com/tommyknows/funcheck/blob/c15f4ec19900ebd410468ccbec5b02e50d8d2efe/prettyprint/prettyprint.go},
organization = {Github},
author = {Ramon Rüttimann},
urldate = "2020-06-18",
}
@ONLINE{prettyprint-orig,
title = {{funcheck/prettyprint.go at 4ce4737 - tommyknows/funcheck}},
year = 2020,
month = May,
day = 31,
url = {https://github.com/tommyknows/funcheck/blob/4ce4737851ceab70d1a9999297a7f03da4975efc/prettyprint/prettyprint.go},
organization = {Github},
author = {Ramon Rüttimann},
urldate = "2020-06-18",
}
@ONLINE{go-lambdas,
title = {{proposal: Go 2: Lightweight anonymous function syntax}},
organization = {Github},
url = {https://github.com/golang/go/issues/21498},
author = {Damien Neil},
year = 2017,
month = Aug,
day = 17,
urldate = "2020-05-16",
}
@ONLINE{java-lambda-expressions,
organization = {Oracle},
url = {https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html},
urldate = "2020-05-16",
}
@ONLINE{java-8-spec,
author = {James Gosling and Bill Joy and Guy Steele and Gilad Bracha and Alex Buckley},
title = {{The Java Language Specification - Java SE 8 Edition}},
url = {https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf},
year = 2015,
month = Feb,
day = 13,
urldate = "2020-05-17",
}
@ONLINE{java-14-spec,
author = {James Gosling and Bill Joy and Guy Steele and Gilad Bracha and Alex Buckley and Daniel Smith and Gavin Bierman},
title = {{The Java Language Specification - Java SE 14 Edition}},
url = {https://docs.oracle.com/javase/specs/jls/se14/jls14.pdf},
year = 2020,
month = Feb,
day = 20,
urldate = "2020-05-17",
}
@ONLINE{go-generics-proposal,
author = {Ian Lance Taylor and Robert Griesemer},
title = {{Type Parameters - Draft Design}},
url = {https://go.googlesource.com/proposal/+/d44c4ded9c1a13dcf715ac641ce760170fbbcf64/design/go2draft-type-parameters.md#type-lists-in-interface-types},
year = 2020,
month = Jun,
day = 16,
urldate = "2020-06-18",
}
@ONLINE{final-java,
author = {{Wikipedia contributors}},
title = "Final (Java) --- {Wikipedia}{,} The Free Encyclopedia",
year = "2020",
url = "https://en.wikipedia.org/w/index.php?title=Final_(Java)&oldid=941659079",
urldate = "2020-04-25",
month = Feb,
day = 19,
}
@ONLINE{fold-wiki,
title = {{Fold (higher-order function) - Wikipedia}},
year = 2020,
month = Feb,
day = 16,
urldate = "2020-04-12",
url = {https:en.wikipedia.org/w/index.php?title=Fold_(higher-order_function)&oldid=941001801},
author = {{Wikipedia contributors}},
}

@ -0,0 +1,8 @@
[0] Config.pm:304> INFO - This is Biber 2.14 running in TOOL mode
[0] Config.pm:307> INFO - Logfile is 'thesis.bib.blg'
[88] biber-darwin:322> INFO - === Fri Apr 10, 2020, 13:34:33
[102] Utils.pm:75> INFO - Globbing data source 'thesis.bib'
[102] Utils.pm:91> INFO - Globbed data source 'thesis.bib' to thesis.bib
[113] Biber.pm:4451> INFO - Looking for bibtex format file 'thesis.bib'
[114] bibtex.pm:1653> INFO - LaTeX decoding ...
[152] bibtex.pm:1471> INFO - Found BibTeX data source 'thesis.bib'

@ -0,0 +1,7 @@
This is makeindex, version 2.15 [TeX Live 2019] (kpathsea + Thai support).
Scanning style file ./thesis.ist.............................done (29 attributes redefined, 0 ignored).
Scanning input file thesis.glo....done (11 entries accepted, 0 rejected).
Sorting entries....done (44 comparisons).
Generating output file thesis.gls....done (25 lines written, 0 warnings).
Output written in thesis.gls.
Transcript written in thesis.glg.

@ -0,0 +1,11 @@
\glossaryentry{AST?\glossentry{ast}|setentrycounter[]{page}\glsnumberformat}{16}
\glossaryentry{SSA?\glossentry{ssa}|setentrycounter[]{page}\glsnumberformat}{16}
\glossaryentry{DAG?\glossentry{dag}|setentrycounter[]{page}\glsnumberformat}{16}
\glossaryentry{copy by value?\glossentry{copy-by-value}|setentrycounter[]{page}\glsnumberformat}{27}
\glossaryentry{EBNF?\glossentry{ebnf}|setentrycounter[]{page}\glsnumberformat}{32}
\glossaryentry{AST?\glossentry{ast}|setentrycounter[]{page}\glsnumberformat}{35}
\glossaryentry{SSA?\glossentry{ssa}|setentrycounter[]{page}\glsnumberformat}{35}
\glossaryentry{stdout?\glossentry{stdout}|setentrycounter[]{page}\glsnumberformat}{54}
\glossaryentry{AST?\glossentry{ast}|setentrycounter[]{page}\glsnumberformat}{62}
\glossaryentry{AST?\glossentry{ast}|setentrycounter[]{page}\glsnumberformat}{63}
\glossaryentry{sum types?\glossentry{sumtypes}|setentrycounter[]{page}\glsnumberformat}{65}

@ -0,0 +1,25 @@
\glossarysection[\glossarytoctitle]{\glossarytitle}\glossarypreamble
\begin{theglossary}\glossaryheader
\glsgroupheading{A}\relax \glsresetentrylist %
\glossentry{ast}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{16}\delimN
\setentrycounter[]{page}\glsnumberformat{35}\delimN
\setentrycounter[]{page}\glsnumberformat{62\delimN 63}}}\glsgroupskip
\glsgroupheading{C}\relax \glsresetentrylist %
\glossentry{copy-by-value}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{27}}}\glsgroupskip
\glsgroupheading{D}\relax \glsresetentrylist %
\glossentry{dag}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{16}}}\glsgroupskip
\glsgroupheading{E}\relax \glsresetentrylist %
\glossentry{ebnf}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{32}}}\glsgroupskip
\glsgroupheading{S}\relax \glsresetentrylist %
\glossentry{ssa}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{16}\delimN
\setentrycounter[]{page}\glsnumberformat{35}}}%
\glossentry{stdout}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{54}}}%
\glossentry{sumtypes}{\glossaryentrynumbers{\relax
\setentrycounter[]{page}\glsnumberformat{65}}}%
\end{theglossary}\glossarypostamble

@ -0,0 +1,210 @@
\ifglsentryexists{dag}{}%
{%
\gls@defglossaryentry{dag}%
{%
name={DAG},%
sort={DAG},%
type={main},%
first={DAG},%
firstplural={DAGs},%
text={DAG},%
plural={DAGs},%
description={Directed Acyclic Graph},%
descriptionplural={Directed Acyclic Graph},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{ast}{}%
{%
\gls@defglossaryentry{ast}%
{%
name={AST},%
sort={AST},%
type={main},%
first={AST},%
firstplural={ASTs},%
text={AST},%
plural={ASTs},%
description={Abstract Syntax Tree, an abstract representation of source code as a tree},%
descriptionplural={Abstract Syntax Tree, an abstract representation of source code as a tree},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{ssa}{}%
{%
\gls@defglossaryentry{ssa}%
{%
name={SSA},%
sort={SSA},%
type={main},%
first={SSA},%
firstplural={SSAs},%
text={SSA},%
plural={SSAs},%
description={Single Static Assignment, an intermediate representation between the AST and the compiled binary that simplifies and improves compiler optimisations},%
descriptionplural={Single Static Assignment, an intermediate representation between the AST and the compiled binary that simplifies and improves compiler optimisations},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{copy-by-value}{}%
{%
\gls@defglossaryentry{copy-by-value}%
{%
name={copy by value},%
sort={copy by value},%
type={main},%
first={copy by value},%
firstplural={copy by values},%
text={copy by value},%
plural={copy by values},%
description={Copy by value refers to the argument-passing style where the supplied arguments are copied. To pass references in Go, the developer needs to use pointers instead},%
descriptionplural={Copy by value refers to the argument-passing style where the supplied arguments are copied. To pass references in Go, the developer needs to use pointers instead},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{ebnf}{}%
{%
\gls@defglossaryentry{ebnf}%
{%
name={EBNF},%
sort={EBNF},%
type={main},%
first={EBNF},%
firstplural={EBNFs},%
text={EBNF},%
plural={EBNFs},%
description={Extended Backus-Naur Form, an extended version of the `Backus-Naur Form, a notation technique to describe programming language syntax},%
descriptionplural={Extended Backus-Naur Form, an extended version of the `Backus-Naur Form, a notation technique to describe programming language syntax},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{stdout}{}%
{%
\gls@defglossaryentry{stdout}%
{%
name={stdout},%
sort={stdout},%
type={main},%
first={stdout},%
firstplural={stdouts},%
text={stdout},%
plural={stdouts},%
description={Standard Output, the default output stream for programs},%
descriptionplural={Standard Output, the default output stream for programs},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%
\ifglsentryexists{sumtypes}{}%
{%
\gls@defglossaryentry{sumtypes}%
{%
name={sum types},%
sort={sum types},%
type={main},%
first={sum types},%
firstplural={sum typess},%
text={sum types},%
plural={sum typess},%
description={Sum types, often also called aggregated types, variant or tagged union is a data structure that can hold one of several, predefined data types. For example, Haskell's \mintinline {haskell}|Either| holds either a value of type A or type B. Similar to that, \mintinline {haskell}|Maybe| can hold either a concrete value, or `Nothing'},%
descriptionplural={Sum types, often also called aggregated types, variant or tagged union is a data structure that can hold one of several, predefined data types. For example, Haskell's \mintinline {haskell}|Either| holds either a value of type A or type B. Similar to that, \mintinline {haskell}|Maybe| can hold either a concrete value, or `Nothing'},%
symbol={\relax },%
symbolplural={\relax },%
user1={},%
user2={},%
user3={},%
user4={},%
user5={},%
user6={},%
long={},%
longplural={},%
short={},%
shortplural={},%
counter={page},%
parent={},%
%
}%
}%

@ -0,0 +1,2 @@
$ gopls check main.go
/tmp/playground/main.go:6:22-23: cannot convert 3 (untyped int constant) to string

@ -0,0 +1,81 @@
\babel@toc {english}{}
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\contentsline {listing}{\numberline {1.1}{\ignorespaces Quicksort implementation in Haskell\relax }}{5}{listing.caption.5}%
\contentsline {listing}{\numberline {1.2}{\ignorespaces Go web server handler function\relax }}{7}{listing.caption.6}%
\contentsline {listing}{\numberline {1.3}{\ignorespaces Constructor with functional options\relax }}{8}{listing.caption.7}%
\contentsline {listing}{\numberline {1.4}{\ignorespaces Example for a functional option\relax }}{8}{listing.caption.8}%
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\contentsline {listing}{\numberline {3.1}{\ignorespaces Example usage for map and fmap\relax }}{20}{listing.caption.10}%
\contentsline {listing}{\numberline {3.2}{\ignorespaces Example usage of map in Go\relax }}{21}{listing.caption.11}%
\contentsline {listing}{\numberline {3.3}{\ignorespaces Example usage of prepend in go\relax }}{22}{listing.caption.13}%
\contentsline {listing}{\numberline {3.4}{\ignorespaces Function headers of the fold functions\relax }}{23}{listing.caption.14}%
\contentsline {listing}{\numberline {3.5}{\ignorespaces foldr and foldl execution order\relax }}{23}{listing.caption.16}%
\contentsline {listing}{\numberline {3.6}{\ignorespaces Example usage of foldr and foldl in go\relax }}{24}{listing.caption.17}%
\contentsline {listing}{\numberline {3.7}{\ignorespaces Example usage of filter in Go\relax }}{25}{listing.caption.18}%
\contentsline {listing}{\numberline {3.8}{\ignorespaces Go Variable Declarations\relax }}{30}{listing.caption.19}%
\contentsline {listing}{\numberline {3.9}{\ignorespaces Go Assignment Operators\relax }}{31}{listing.caption.20}%
\contentsline {listing}{\numberline {3.10}{\ignorespaces Go scoping issue with recursive functions\relax }}{32}{listing.caption.22}%
\contentsline {listing}{\numberline {3.11}{\ignorespaces Fixing the scope issue on recursive functions\relax }}{32}{listing.caption.23}%
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\contentsline {listing}{\numberline {4.1}{\ignorespaces Godoc for the new built-in functions\autocite {new-builtins-godoc}\relax }}{37}{listing.caption.27}%
\contentsline {listing}{\numberline {4.2}{\ignorespaces Registering new built-in functions\autocite {new-builtins-universe}\relax }}{38}{listing.caption.28}%
\contentsline {listing}{\numberline {4.3}{\ignorespaces fmap implementation in Go\relax }}{40}{listing.caption.30}%
\contentsline {listing}{\numberline {4.4}{\ignorespaces Improved implementation of fmap\relax }}{40}{listing.caption.31}%
\contentsline {listing}{\numberline {4.5}{\ignorespaces fmap AST translation\autocite {fmap-walk-implementation}\relax }}{41}{listing.caption.32}%
\contentsline {listing}{\numberline {4.6}{\ignorespaces prepend implementation in Go\relax }}{41}{listing.caption.34}%
\contentsline {listing}{\numberline {4.7}{\ignorespaces prepend AST translation\autocite {prepend-walk-implementation}\relax }}{42}{listing.caption.35}%
\contentsline {listing}{\numberline {4.8}{\ignorespaces fold implementation in Go\relax }}{42}{listing.caption.37}%
\contentsline {listing}{\numberline {4.9}{\ignorespaces fold AST translation\autocite {fold-walk-implementation}\relax }}{43}{listing.caption.38}%
\contentsline {listing}{\numberline {4.10}{\ignorespaces filter implementation in Go\relax }}{43}{listing.caption.40}%
\contentsline {listing}{\numberline {4.11}{\ignorespaces filter AST translation\autocite {filter-walk-implementation}\relax }}{44}{listing.caption.41}%
\contentsline {listing}{\numberline {4.12}{\ignorespaces Illustrating the difference between Go code and it's AST code\relax }}{45}{listing.caption.43}%
\contentsline {listing}{\numberline {4.13}{\ignorespaces Handling the basic AST types in funcheck\autocite {funcheck-ast-types}\relax }}{49}{listing.caption.44}%
\contentsline {listing}{\numberline {4.14}{\ignorespaces Illustration of an assignment node and corresponding positions\autocite {ast-positions}\relax }}{50}{listing.caption.45}%
\contentsline {listing}{\numberline {4.15}{\ignorespaces Illustration of a function literal assignment\autocite {ast-positions}\relax }}{51}{listing.caption.46}%
\contentsline {listing}{\numberline {4.16}{\ignorespaces Testing a code analyser with the `analysistest' package\relax }}{52}{listing.caption.47}%
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\contentsline {listing}{\numberline {5.1}{\ignorespaces Demonstration of the new built-in functions\relax }}{54}{listing.caption.48}%
\contentsline {listing}{\numberline {5.2}{\ignorespaces Pretty-printing declarations in idiomatic Go\relax }}{56}{listing.caption.49}%
\contentsline {listing}{\numberline {5.3}{\ignorespaces Pretty-printing declarations in functional Go\relax }}{57}{listing.caption.50}%
\contentsline {listing}{\numberline {5.4}{\ignorespaces Quicksort implementations compared\relax }}{58}{listing.caption.51}%
\contentsline {listing}{\numberline {5.5}{\ignorespaces Comparison Java Streams and functional Go\relax }}{59}{listing.caption.52}%
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\addvspace {10\p@ }
\contentsline {listing}{\numberline {1}{\ignorespaces Functional Options for a simple web server\relax }}{81}{listing.caption.61}%
\contentsline {listing}{\numberline {2}{\ignorespaces Example on how to mutate data in Go\relax }}{83}{listing.caption.62}%
\contentsline {listing}{\numberline {3}{\ignorespaces Example on how shadowing works on block scopes\relax }}{84}{listing.caption.63}%
\contentsline {listing}{\numberline {4}{\ignorespaces foldl and foldl' strictness\autocite {fold-types}\relax }}{85}{listing.caption.64}%
\contentsline {listing}{\numberline {5}{\ignorespaces Working around the missing foldl implementation in Go\relax }}{86}{listing.caption.65}%
\contentsline {listing}{\numberline {6}{\ignorespaces The original prettyprint implementation\autocite {prettyprint-orig}\relax }}{90}{listing.caption.66}%
\contentsline {listing}{\numberline {7}{\ignorespaces The refactored, functional prettyprint implementation\autocite {prettyprint-functional}\relax }}{92}{listing.caption.67}%
\contentsline {listing}{\numberline {8}{\ignorespaces Demonstration of how sum types can be imitated with interfaces\relax }}{93}{listing.caption.68}%

@ -0,0 +1,123 @@
%!
/pdfmark where{pop}
{/globaldict where{pop globaldict}{userdict}ifelse/pdfmark/cleartomark load put}
ifelse
[
/Title(\376\377\000S\000u\000m\000m\000a\000r\000y)
/Action/GoTo/Dest(chapter*.1)cvn
/OUT pdfmark
[
/Title(\376\377\000A\000b\000s\000t\000r\000a\000c\000t)
/Action/GoTo/Dest(chapter*.3)cvn
/OUT pdfmark
[
/Title(\376\377\000P\000r\000e\000f\000a\000c\000e)
/Action/GoTo/Dest(chapter*.5)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000\040\000I\000n\000t\000r\000o\000d\000u\000c\000t\000i\000o\000n)
/Count 6
/Action/GoTo/Dest(chapter.1)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0001\000\040\000L\000e\000a\000r\000n\000i\000n\000g\000\040\000F\000u\000n\000c\000t\000i\000o\000n\000a\000l\000\040\000P\000r\000o\000g\000r\000a\000m\000m\000i\000n\000g)
/Action/GoTo/Dest(section.1.1)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0002\000\040\000H\000a\000s\000k\000e\000l\000l)
/Action/GoTo/Dest(section.1.2)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0003\000\040\000G\000o\000a\000l\000s)
/Action/GoTo/Dest(section.1.3)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0004\000\040\000W\000h\000y\000\040\000G\000o)
/Count 1
/Action/GoTo/Dest(section.1.4)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0004\000.\0001\000\040\000G\000o\000\040\000S\000l\000i\000c\000e\000s)
/Action/GoTo/Dest(subsection.1.4.1)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0005\000\040\000E\000x\000i\000s\000t\000i\000n\000g\000\040\000W\000o\000r\000k)
/Action/GoTo/Dest(section.1.5)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000.\0006\000\040\000W\000o\000r\000k\000\040\000t\000o\000\040\000b\000e\000\040\000d\000o\000n\000e)
/Action/GoTo/Dest(section.1.6)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000\040\000M\000e\000t\000h\000o\000d\000o\000l\000o\000g\000y)
/Count 2
/Action/GoTo/Dest(chapter.2)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000.\0001\000\040\000S\000l\000i\000c\000e\000\040\000H\000e\000l\000p\000e\000r\000\040\000F\000u\000n\000c\000t\000i\000o\000n\000s)
/Count 3
/Action/GoTo/Dest(section.2.1)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000.\0001\000.\0001\000\040\000C\000h\000o\000o\000s\000i\000n\000g\000\040\000t\000h\000e\000\040\000f\000u\000n\000c\000t\000i\000o\000n\000s)
/Action/GoTo/Dest(subsection.2.1.1)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000.\0001\000.\0002\000\040\000R\000e\000q\000u\000i\000r\000e\000d\000\040\000S\000t\000e\000p\000s)
/Action/GoTo/Dest(subsection.2.1.2)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000.\0001\000.\0003\000\040\000P\000r\000e\000p\000e\000n\000d)
/Action/GoTo/Dest(subsection.2.1.3)cvn
/OUT pdfmark
[
/Title(\376\377\0002\000.\0002\000\040\000F\000u\000n\000c\000t\000i\000o\000n\000a\000l\000\040\000C\000h\000e\000c\000k)
/Action/GoTo/Dest(section.2.2)cvn
/OUT pdfmark
[
/Title(\376\377\0003\000\040\000I\000m\000p\000l\000e\000m\000e\000n\000t\000a\000t\000i\000o\000n)
/Count 1
/Action/GoTo/Dest(chapter.3)cvn
/OUT pdfmark
[
/Title(\376\377\0003\000.\0001\000\040\000S\000l\000i\000c\000e\000\040\000H\000e\000l\000p\000e\000r\000\040\000F\000u\000n\000c\000t\000i\000o\000n\000s)
/Count 1
/Action/GoTo/Dest(section.3.1)cvn
/OUT pdfmark
[
/Title(\376\377\0003\000.\0001\000.\0001\000\040\000I\000m\000p\000l\000e\000m\000e\000n\000t\000i\000n\000g\000\040\000P\000r\000e\000p\000e\000n\000d)
/Action/GoTo/Dest(subsection.3.1.1)cvn
/OUT pdfmark
[
/Title(\376\377\0004\000\040\000A\000p\000p\000l\000i\000c\000a\000t\000i\000o\000n)
/Action/GoTo/Dest(chapter.4)cvn
/OUT pdfmark
[
/Title(\376\377\0005\000\040\000E\000x\000p\000e\000r\000i\000m\000e\000n\000t\000s\000\040\000a\000n\000d\000\040\000R\000e\000s\000u\000l\000t\000s)
/Action/GoTo/Dest(chapter.5)cvn
/OUT pdfmark
[
/Title(\376\377\0006\000\040\000D\000i\000s\000c\000u\000s\000s\000i\000o\000n)
/Action/GoTo/Dest(chapter.6)cvn
/OUT pdfmark
[
/Title(\376\377\000L\000i\000s\000t\000\040\000o\000f\000\040\000s\000o\000u\000r\000c\000e\000\040\000c\000o\000d\000e\000s)
/Action/GoTo/Dest(chapter*.26)cvn
/OUT pdfmark
[
/Title(\376\377\000L\000i\000s\000t\000\040\000o\000f\000\040\000F\000i\000g\000u\000r\000e\000s)
/Action/GoTo/Dest(chapter*.27)cvn
/OUT pdfmark
[
/Title(\376\377\000L\000i\000s\000t\000\040\000o\000f\000\040\000T\000a\000b\000l\000e\000s)
/Action/GoTo/Dest(chapter*.28)cvn
/OUT pdfmark
[
/Title(\376\377\000A\000p\000p\000e\000n\000d\000i\000c\000e\000s)
/Count 1
/Action/GoTo/Dest(section*.31)cvn
/OUT pdfmark
[
/Title(\376\377\0001\000\040\000A\000n\000a\000l\000y\000s\000i\000s\000\040\000o\000f\000\040\000f\000u\000n\000c\000t\000i\000o\000n\000\040\000o\000c\000c\000u\000r\000r\000e\000n\000c\000e\000s\000\040\000i\000n\000\040\000H\000a\000s\000k\000e\000l\000l\000\040\000c\000o\000d\000e)
/Action/GoTo/Dest(section.1..1)cvn
/OUT pdfmark

Binary file not shown.

@ -0,0 +1,90 @@
<?xml version="1.0" standalone="yes"?>
<!-- logreq request file -->
<!-- logreq version 1.0 / dtd version 1.0 -->
<!-- Do not edit this file! -->
<!DOCTYPE requests [
<!ELEMENT requests (internal | external)*>
<!ELEMENT internal (generic, (provides | requires)*)>
<!ELEMENT external (generic, cmdline?, input?, output?, (provides | requires)*)>
<!ELEMENT cmdline (binary, (option | infile | outfile)*)>
<!ELEMENT input (file)+>
<!ELEMENT output (file)+>
<!ELEMENT provides (file)+>
<!ELEMENT requires (file)+>
<!ELEMENT generic (#PCDATA)>
<!ELEMENT binary (#PCDATA)>
<!ELEMENT option (#PCDATA)>
<!ELEMENT infile (#PCDATA)>
<!ELEMENT outfile (#PCDATA)>
<!ELEMENT file (#PCDATA)>
<!ATTLIST requests
version CDATA #REQUIRED
>
<!ATTLIST internal
package CDATA #REQUIRED
priority (9) #REQUIRED
active (0 | 1) #REQUIRED
>
<!ATTLIST external
package CDATA #REQUIRED
priority (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) #REQUIRED
active (0 | 1) #REQUIRED
>
<!ATTLIST provides
type (static | dynamic | editable) #REQUIRED
>
<!ATTLIST requires
type (static | dynamic | editable) #REQUIRED
>
<!ATTLIST file
type CDATA #IMPLIED
>
]>
<requests version="1.0">
<internal package="biblatex" priority="9" active="0">
<generic>latex</generic>
<provides type="dynamic">
<file>thesis.bcf</file>
</provides>
<requires type="dynamic">
<file>thesis.bbl</file>
</requires>
<requires type="static">
<file>blx-dm.def</file>
<file>blx-compat.def</file>
<file>biblatex.def</file>
<file>standard.bbx</file>
<file>numeric.bbx</file>
<file>numeric-comp.bbx</file>
<file>ieee.bbx</file>
<file>numeric-comp.cbx</file>
<file>ieee.cbx</file>
<file>biblatex.cfg</file>
<file>english.lbx</file>
<file>german.lbx</file>
<file>nswissgerman.lbx</file>
</requires>
</internal>
<external package="biblatex" priority="5" active="0">
<generic>biber</generic>
<cmdline>
<binary>biber</binary>
<infile>thesis</infile>
</cmdline>
<input>
<file>thesis.bcf</file>
</input>
<output>
<file>thesis.bbl</file>
</output>
<provides type="dynamic">
<file>thesis.bbl</file>
</provides>
<requires type="dynamic">
<file>thesis.bcf</file>
</requires>
<requires type="editable">
<file>thesis.bib</file>
</requires>
</external>
</requests>

@ -0,0 +1,407 @@
% -*- mode: latex; coding: utf-8 -*-
% !TEX TS-program = pdflatexmk
% !TEX encoding = UTF-8 Unicode
%\RequirePackage[hyphens]{url}
\documentclass[%
a4paper,
twoside,
numbers=noenddot,
parskip=half,
open=any,
headsepline,
english, % german, english
ba % ba, pa
]{zhawthesis}
\usepackage{etoolbox}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Parameters
% - Adjust these to your needs:
\title{Functional Go}
\subtitle{...An Easier Introduction to Functional Programming}
\author{% Komma getrennt
Ramon Rüttimann
}
\newcommand\twodigits[1]{\ifnum#1<10 0#1\else #1\fi}
\date{\twodigits{\the\day}.\twodigits{\number\month}.\the\year}
\major{Computer Science} % Studiengang
\zhawsemester{Spring 2020}
\zhawinstitute{init}
\zhawlogocolour{pantone2945} % pantone2945, cmyk, sw
\mainsupervisor{Dr. G. Burkert}
\subsupervisor{Dr. K. Rege}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Base packages used by the template (any commonly used packages)
%\PassOptionsToPackage{hyphens}{url}\usepackage{hyperref}
\usepackage{float}
\usepackage{graphicx}
\graphicspath{{figures/}}
\DeclareGraphicsExtensions{.pdf,.png,.jpg,.gif}
\usepackage{tabularx}
\usepackage{longtable}
\usepackage{booktabs}
\usepackage{todonotes}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Custom packages
% - Add packages used by your thesis here:
%\usepackage{hyperref}
%\PassOptionsToPackage{hyphens}{url}\usepackage{hyperref}
\hypersetup{
colorlinks = true, %Colours links instead of ugly boxes
%urlcolor = blue, %Colour for external hyperlinks
linkcolor = blue, %Colour of internal links
citecolor = blue %Colour of citations
}
\usepackage[newfloat]{minted}
\usepackage{listings}
\newenvironment{code}{\captionsetup{type=listing}}{}
\SetupFloatingEnvironment{listing}{name=Source Code,placement=H}
\definecolor{bg}{rgb}{0.95,0.95,0.95}
\newminted{bash}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newminted{bnf}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newminted{c}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newminted{go}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newminted{haskell}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newminted{java}{breaklines,breakbytoken,tabsize=2,bgcolor=bg}
\newmintedfile{go}{breaklines,breakanywhere,tabsize=2,bgcolor=bg,linenos,stepnumber=5,numberfirstline}
\newcommand{\gofilerange}[4][]{%
\immediate\write18{./utils/delim -file="#2" -start="#3" -end="#4"}%
\IfFileExists{code.lineno}%
{\CatchFileEdef{\linenumber}{./code.lineno}{\endlinechar=-1 }}%
{\def\linenumber{0}}%
\edef\flags{firstnumber=\linenumber,#1}%
\expandafter\gofile\expandafter[\flags]{./code.snippet}}
\newcommand{\unchapter}[1]{%
\begingroup
\let\@makesectionhead\@gobble % make \@makechapterhead do nothing
\section{#1}
\endgroup
}
\makeatother
%\sloppy
\usepackage[
backend=biber,
hyperref=true,
style=ieee,
dashed=false,
]{biblatex}
\usepackage{xurl}
\usepackage[skip=0pt]{caption}
\usepackage[toc,page]{appendix}
\usepackage{hyperref}
\usepackage{glossaries}
\usepackage{pdfpages}
%\usepackage{listings}
\makeglossaries
%\usepackage{csquotes}
\AtBeginEnvironment{quote}{\itshape}
%\bibliography{thesis}
\addbibresource{thesis.bib}
\begin{document}
\frontmatter
\maketitle
\cleardoublepage % chktex 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Declaration of Originality
\makedeclarationoforiginality % chktex 1
\cleardoublepage % chktex 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Abstract}
\label{ch:abstract} % chktex 24
\input{chapters/01_abstract.tex}
\chapter{Zusammenfassung}
\label{ch:summary} % chktex 24
\input{chapters/02_zusammenfassung.tex}
\IfLanguageName{nswissgerman}{\chapter{Vorwort}}{\chapter{Preface}}
\label{ch:preface} % chktex 24
\input{chapters/10_preface.tex}
\cleardoublepage % chktex 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\mainmatter % chktex 1
\tableofcontents
\IfLanguageName{nswissgerman}{\chapter{Einleitung}}{\chapter{Introduction}}
\label{ch:introduction} % chktex 24
\input{chapters/20_introduction.tex}
\chapter{About Go}
\label{ch:about-go}
\input{chapters/25_about_go.tex}
% DISABLE RELATED WORK AS I PUT THAT INTO THE INTRO
%\IfLanguageName{nswissgerman}{\chapter{Verwandte Arbeit}}{\chapter{Related Work}}
%\label{ch:related-work} % chktex 24
%\input{chapters/30_related_work.tex}
\IfLanguageName{nswissgerman}{\chapter{Methoden}}{\chapter{Methodology}}
\label{ch:methodology} % chktex 24
\input{chapters/30_methodology.tex}
\chapter{Implementation}
\label{ch:implementation} % chktex 24
\input{chapters/40_implementation.tex}
\chapter{Application}
\label{ch:application} % chktex 24
\input{chapters/50_application.tex}
\IfLanguageName{nswissgerman}{\chapter{Resultate}}{\chapter{Results}}
\label{ch:results} % chktex 24
\input{chapters/60_results.tex}
\IfLanguageName{nswissgerman}{\chapter{Diskussion}}{\chapter{Discussion}}
\label{ch:discussion} % chktex 24
\input{chapters/70_discussion.tex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\backmatter % chktex 1
% \let\clearpage\relax
% \vspace{-4em}
\printbibliography
% \endgroup
\renewcommand{\lstlistlistingname}{List of source codes}
\lstlistoflistings
% \begingroup
% \let\clearpage\relax
% \vspace{-4em}
\listoffigures
% \endgroup
% \begingroup
% \let\clearpage\relax
% \vspace{-4em}
\listoftables
\clearpage
\phantomsection
\addtocounter{chapter}{1}
\addcontentsline{toc}{chapter}{%
Glossary}
\printglossaries
% \endgroup
\cleardoublepage % chktex 1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\appendix
\begin{appendices}
\input{chapters/80_appendix.tex}
%\section{Example for Functional Options}\label{appendix:funcopts}
%\begin{code}
%\captionof{listing}{Functional Options for a simple Webserver}
%\gofile{../work/examples/functional-options/main.go}
%\end{code}
%\section{Analysis of function occurrences in Haskell code}\label{appendix:function-occurrences}
%The results of the analysis have been aquired by running the following command
%from the root of the git repository\cite{git-repo}:
%\begin{bashcode}
%./work/common-list-functions/count-function.sh "map " " : " "fold" "filter " "reverse " "take " "drop " "maximum" "sum " "zip " "product " "minimum " "reduce "
%\end{bashcode}
%\section{Mutating variables in Go}\label{appendix:mutation}
%\begin{code}
%\captionof{listing}{Example on how to mutate complex types in Go}
%\gofile{../work/examples/mutate/main.go}
%\end{code}
%\section{Shadowing variables in Go}\label{appendix:shadowing}
%\begin{code}
%\captionof{listing}{Example on how shadowing works on block scopes}
%\gofile{../work/examples/shadowing/main.go}
%\end{code}
%\section{Workaround for the missing foldl' implementation in Go}\label{appendix:foldl-go}
%\begin{code}
%\captionof{listing}{Working around the missing foldl implementation in Go}
%\label{code:foldl-go}
%\gofile{../work/examples/foldl-workaround/main.go}
%\begin{bashcode}
%$> fgo run .
%0
%panic: runtime error: invalid memory address or nil pointer dereference
%[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x109e945]
%goroutine 1 [running]:
%main.what(0x2, 0x0, 0x2)
%/tmp/map/main.go:16 +0x5
%main.main()
%/tmp/map/main.go:12 +0x187
%exit status 2
%\end{bashcode}
%\end{code}
%\section{Prettyprint implementation}\label{appendix:prettyprint-func}
%\begin{code}
%\captionof{listing}{The original prettyprint implementation}
%\gofile{../work/funcheck/prettyprint/prettyprint.go}
%\end{code}
%\begin{code}
%\captionof{listing}{The refactored, functional prettyprint implementation}
%\begin{gocode}
%package prettyprint
%import (
%"bytes"
%"fmt"
%"go/ast"
%"go/printer"
%"go/token"
%"golang.org/x/tools/go/analysis"
%)
%var Analyzer = &analysis.Analyzer{
%Name: "prettyprint",
%Doc: "prints positions",
%Run: run,
%}
%type null struct{}
%func checkDecl(as *ast.DeclStmt, fset *token.FileSet) {
%fmt.Printf("Declaration %q: %v\n", render(fset, as), as.Pos())
%check := func(_ null, spec ast.Spec) (n null) {
%val, ok := spec.(*ast.ValueSpec)
%if !ok {
%return
%}
%if val.Values != nil {
%return
%}
%if _, ok := val.Type.(*ast.FuncType); !ok {
%return
%}
%fmt.Printf("\tIdent %q: %v\n", render(fset, val), val.Names[0].Pos())
%return
%}
%if decl, ok := as.Decl.(*ast.GenDecl); ok {
%_ = foldl(check, null{}, decl.Specs)
%}
%}
%func checkAssign(as *ast.AssignStmt, fset *token.FileSet) {
%fmt.Printf("Assignment %q: %v\n", render(fset, as), as.Pos())
%check := func(_ null, expr ast.Expr) (n null) {
%ident, ok := expr.(*ast.Ident) // Lhs always is an "IdentifierList"
%if !ok {
%return
%}
%fmt.Printf("\tIdent %q: %v\n", ident.String(), ident.Pos())
%switch {
%case ident.Name == "_":
%fmt.Printf("\t\tBlank Identifier!\n")
%case ident.Obj == nil:
%fmt.Printf("\t\tDecl is not in the same file!\n")
%default:
%// make sure the declaration has a Pos func and get it
%declPos := ident.Obj.Decl.(ast.Node).Pos()
%fmt.Printf("\t\tDecl %q: %v\n", render(fset, ident.Obj.Decl), declPos)
%}
%return
%}
%_ = foldl(check, null{}, as.Lhs)
%}
%func run(pass *analysis.Pass) (interface{}, error) {
%inspect := func(_ null, file *ast.File) (n null) {
%ast.Inspect(file, func(n ast.Node) bool {
%switch as := n.(type) {
%case *ast.DeclStmt:
%checkDecl(as, pass.Fset)
%case *ast.AssignStmt:
%checkAssign(as, pass.Fset)
%}
%return true
%})
%return
%}
%_ = foldl(inspect, null{}, pass.Files)
%return nil, nil
%}
%// render returns the pretty-print of the given node
%func render(fset *token.FileSet, x interface{}) string {
%var buf bytes.Buffer
%if err := printer.Fprint(&buf, fset, x); err != nil {
%panic(err)
%}
%return buf.String()
%}
%\end{gocode}
%\end{code}
%% - Add your appendix here:
%\todo[inline]{
%Anhang/Appendix:
%\quad -- Projektmanagement: \\ % chktex 8
%\qquad -- Offizielle Aufgabenstellung, Projektauftrag \\ % chktex 8
%\qquad -- (Zeitplan) \\ % chktex 8
%\qquad -- (Besprechungsprotokolle oder Journals) % chktex 8
%\quad -- Weiteres: \\ % chktex 8
%\qquad -- CD/USB-Stick mit dem vollständigen Bericht als PDF-File inklusive Film- und Fotomaterial \\ % chktex 8
%\qquad -- (Schaltpläne und Ablaufschemata) \\ % chktex 8
%\qquad -- (Spezifikation u. Datenblätter der verwendeten Messgeräte und/oder Komponenten) \\ % chktex 8
%\qquad -- (Berechnungen, Messwerte, Simulationsresultate) \\ % chktex 8
%\qquad -- (Stoffdaten) \\ % chktex 8
%\qquad -- (Fehlerrechnungen mit Messunsicherheiten) \\ % chktex 8
%\qquad -- (Grafische Darstellungen, Fotos) \\ % chktex 8
%\qquad -- (Datenträger mit weiteren Daten (z. B. Software-Komponenten) inkl. Verzeichnis der auf diesem Datenträger abgelegten Dateien) \\ % chktex 8
%\qquad -- (Softwarecode) % chktex 8
%}
\end{appendices}
\end{document}

@ -0,0 +1,29 @@
# Delim
This is a small helper utility for building the latex document.
It is called by [thesis.tex](../thesis.tex) with the following `newcommand`:
```tex
\newcommand{\gofilerange}[4][]{%
\immediate\write18{./utils/delim -file="#2" -start="#3" -end="#4"}
\IfFileExists{code.lineno}
{\CatchFileEdef{\linenumber}{./code.lineno}{\endlinechar=-1 }}
{\def\linenumber{0}}
\edef\flags{firstnumber=\linenumber,#1}
\expandafter\gofile\expandafter[\flags]{./code.snippet}
}
```
Basically, `delim` receives the filename and a start- and end-comment.
It then writes the files content between the two comments into `code.snippet`,
and the starting line number into `code.lineno`.
These are then used by the `minted` package to display the code section
within the document.
Use it in the document like so:
```tex
\gofilerange{this/file.go}{start-section}{end-section}
```

Binary file not shown.

@ -0,0 +1,3 @@
module github.zhaw.ch/ruettram/bachelor/thesis/utils
go 1.14

@ -0,0 +1,82 @@
package main
import (
"bufio"
"flag"
"log"
"os"
"strconv"
"strings"
)
const (
targetFile = "code"
snippetEnding = ".snippet"
lineNumberEnding = ".lineno"
)
func main() {
start := flag.String("start", "", "the starting delimiter, uncommented")
end := flag.String("end", "", "the ending delimiter, uncommented")
sourceFile := flag.String("file", "", "the source file")
flag.Parse()
// this could be parameterised at some point
*start = "// " + *start
*end = "// " + *end
file, err := os.Open(*sourceFile)
if err != nil {
log.Fatal(err)
}
defer file.Close()
codeDest, err := os.Create(targetFile + snippetEnding)
if err != nil {
log.Fatal(err)
}
defer codeDest.Close()
lineDest, err := os.Create(targetFile + lineNumberEnding)
if err != nil {
log.Fatal(err)
}
defer lineDest.Close()
scanner := bufio.NewScanner(file)
// find start
for lineno := gotoStart(scanner, *start); lineno != -1; lineno = gotoStart(scanner, *start) {
// write line number
_, _ = lineDest.WriteString(strconv.Itoa(lineno))
// write source cod
_, _ = codeDest.WriteString(strings.ReplaceAll(scanner.Text(), *start, "// ...") + "\n")
// scan until end and write
for scanner.Scan() {
if strings.TrimSpace(scanner.Text()) == *end {
_, _ = codeDest.WriteString(strings.ReplaceAll(scanner.Text(), *end, "// ...") + "\n")
break
}
_, _ = codeDest.WriteString(scanner.Text() + "\n")
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
_ = codeDest.Sync()
_ = lineDest.Sync()
}
func gotoStart(s *bufio.Scanner, start string) (linenumber int) {
for s.Scan() {
if strings.TrimSpace(s.Text()) == start {
return linenumber
}
linenumber++
}
return -1
}

@ -0,0 +1,252 @@
%%
%% This is file `zhawthesis.cls',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% zhawthesis.dtx (with options: `class')
%% ----------------------------------------------------------------
%% zhawthesis --- A LaTeX class for writing a thesis at ZHAW.
%% E-mail: camerden@students.zhaw.ch
%% Released under the LaTeX Project Public License v1.3c or later
%% See http://www.latex-project.org/lppl.txt
%% ----------------------------------------------------------------
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{zhawthesis}[2019/02/28 v1.0 Initial version]
%% ========================================================================== %%
%% Thesis class %%
%% ========================================================================== %%
\def\zhaw@babellangde{nswissgerman}
\def\zhaw@babellangen{english}
\newcommand{\zhaw@lang}{de}
\newcommand{\zhaw@babellang}{\zhaw@langde}
\newif\if@german\@germantrue
\newcommand{\zhaw@thesistype}{}
\newcommand{\zhaw@thesistypelong}{}
\DeclareOption{ba}{
\renewcommand{\zhaw@thesistype}{BA}
\renewcommand{\zhaw@thesistypelong}{%
\if@german{Bachelorarbeit}\else{Bachelor thesis}\fi%
}
}
\DeclareOption{pa}{
\renewcommand{\zhaw@thesistype}{PA}
\renewcommand{\zhaw@thesistypelong}{%
\if@german{Projektarbeit}\else{Project work}\fi%
}
}
\DeclareOption{german}{
\@germantrue
\renewcommand{\zhaw@lang}{de}
\renewcommand{\zhaw@babellang}{\zhaw@babellangde}
\PassOptionsToClass{\zhaw@babellang}{scrbook}
}
\DeclareOption{english}{
\@germanfalse
\renewcommand{\zhaw@lang}{en}
\renewcommand{\zhaw@babellang}{\zhaw@babellangen}
\PassOptionsToClass{\zhaw@babellang}{scrbook}
}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrbook}}
\ProcessOptions
\RequirePackage[T1]{fontenc}
\RequirePackage[utf8]{inputenc}
\LoadClass[listof=totoc,bibliography=totoc]{scrbook}
\RequirePackage{microtype}
\RequirePackage{graphicx}
\if@german
\RequirePackage[\zhaw@babellangen,main=\zhaw@babellangde]{babel}
\else
\RequirePackage[\zhaw@babellangde,main=\zhaw@babellangen]{babel}
\fi
\babeltags{de=\zhaw@babellangde,en=\zhaw@babellangen}
\RequirePackage{iflang}
\RequirePackage[autostyle=try,strict=true,german=swiss,english=british]{csquotes}
\RequirePackage[output-decimal-marker={.},group-separator={'}]{siunitx}
\sisetup{detect-all}
\RequirePackage[pdfpagelabels]{hyperref}
\hypersetup{%
unicode,
pdfauthor={\@author},
pdftitle={\@title},
pdfsubject={\zhaw@thesistypelong},
pdfkeywords={Thesis;LaTeX}, % TODO: Complete
pdfcreator={pdfLaTeX},
pdfduplex={DuplexFlipLongEdge},
pdflang={\zhaw@lang},
bookmarksopen,
bookmarksnumbered
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage[automark]{scrlayer-scrpage}
\automark[chapter]{chapter}
\clearpairofpagestyles
\lehead{\@title}
\rohead{\@author}
\ofoot[\pagemark]{\pagemark}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\zhaw@institute}{}
\providecommand{\zhawinstitute}[1]{\renewcommand{\zhaw@institute}{#1}}
\newcommand{\zhaw@logocolour}{pantone2945}
\providecommand{\zhawlogocolour}[1]{\renewcommand{\zhaw@logocolour}{#1}}
\newcommand{\zhaw@major}{}
\providecommand{\major}[1]{\renewcommand{\zhaw@major}{#1}}
\newcommand{\zhaw@semester}{}
\providecommand{\zhawsemester}[1]{\renewcommand{\zhaw@semester}{#1}}
\newcommand{\zhaw@mainsupervisor}{}
\providecommand{\mainsupervisor}[1]{\renewcommand{\zhaw@mainsupervisor}{#1}}
\newcommand{\zhaw@subsupervisor}{}
\providecommand{\subsupervisor}[1]{\renewcommand{\zhaw@subsupervisor}{#1}}
\newcommand\zhaw@industrypartner{}
\providecommand{\industrypartner}[1]{\renewcommand{\zhaw@industrypartner}{#1}}
\newcommand{\zhaw@extsupervisor}{}
\providecommand{\externalsupervisor}[1]{\renewcommand{\zhaw@extsupervisor}{#1}}
\newcommand{\zhaw@titlepagerow}[2]{%
\begin{minipage}[t]{0.3\textwidth}
\hrule\vskip 5mm
\textbf{#1}
\end{minipage}
% \hskip 0.03\textwidth
\hfil
\begin{minipage}[t]{0.67\textwidth}
\hrule\vskip 5mm
#2 \\
\end{minipage}%
}
\newcommand{\zhaw@maketitlepage}{
\thispagestyle{empty}
\clearpage
\begin{titlepage}
\sffamily
% Logo
\begin{picture}(0,0)
\put(-30,-50){
\includegraphics[width=84.2mm]{logos/zhaw/\zhaw@lang-zhaw-\zhaw@institute-\zhaw@logocolour}
}
\end{picture}
\vskip 10mm
\hskip 26mm
\begin{minipage}[b]{0.91\textwidth}
\vskip 20mm
{\huge
% Projekt Name (max. 2 Zeilen)
\textbf{\underline{{\zhaw@thesistypelong} in {\zhaw@major}}} \\
\textbf{\underline{{\zhaw@semester}}} \\
% Projekt Titel (max. 4 Zeilen)
{
\huge{\@title} \\[1.25ex]
\large{\@subtitle}
}
\vspace{9mm}
}
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Autoren}{Author}}{%
\@author \\
}
\if\zhaw@mainsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Hauptbetreuung}{Main supervisor}}{%
\zhaw@mainsupervisor \\
}
\fi
\if\zhaw@subsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Nebenbetreuung}{Sub supervisor}}{%
\zhaw@subsupervisor \\
}
\fi
\if\zhaw@industrypartner\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Industriepartner}{Industrial partner}}{%
\zhaw@industrypartner \\
}
\fi
\if\zhaw@extsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Externe Betreuung}{External supervisor}}{%
\zhaw@extsupervisor \\
}
\fi
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Datum}{Date}}{%
\@date \\
}
\end{minipage}
\vskip 5mm
\end{titlepage}
}
\renewcommand{\maketitle}{\zhaw@maketitlepage}
\RequirePackage{pdfpages}
\providecommand{\makedeclarationoforiginality}{%
\cleardoublepage%
\if@german%
\includepdf{includes/Erklaerung_Selbstaendigkeit_SoE_\zhaw@thesistype_de.pdf}
\else%
\includepdf{includes/Declaration_of_Originality_SoE_\zhaw@thesistype_en.pdf}
\fi%
}
\AtBeginDocument{%
\pagestyle{scrheadings}
% Set 1st level itemize bullet symbol to --
\def\labelitemi{--}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\providecommand\norm[1]{\left\lVert#1\right\rVert}
\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
\hbox{}\nobreak\hfil(#1)%
\parfillskip=0pt \finalhyphendemerits=0 \endgraf}}
%%
%% Copyright (C) 2019 by Dennis Camera <camerden@students.zhaw.ch>
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License (LPPL), either
%% version 1.3c of this license or (at your option) any later
%% version. The latest version of this license is in the file:
%%
%% http://www.latex-project.org/lppl.txt
%%
%% This work is "maintained" (as per LPPL maintenance status).
%%
%% This work consists of the file zhawthesis.dtx
%% and the derived files zhawthesis.ins,
%% zhawthesis.pdf and
%% zhawthesis.cls.
%%
%%
%% End of file `zhawthesis.cls'.

@ -0,0 +1,362 @@
% \iffalse meta-comment
% !TEX program = pdfLaTeX
%<*internal>
\iffalse
%</internal>
%<*readme>
----------------------------------------------------------------
zhawthesis --- A LaTeX class for writing a thesis at ZHAW.
E-mail: camerden@students.zhaw.ch
Released under the LaTeX Project Public License v1.3c or later
See http://www.latex-project.org/lppl.txt
----------------------------------------------------------------
The zhawthesis class provides a framework to build your thesis
around.
Please note: zhawthesis is not officially endorsed by the
ZHAW Zurich University of Applied Sciences!
%</readme>
%<*internal>
\fi
\def\nameofplainTeX{plain}
\ifx\fmtname\nameofplainTeX\else
\expandafter\begingroup
\fi
%</internal>
%<*install>
\input docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble
----------------------------------------------------------------
zhawthesis --- A LaTeX class for writing a thesis at ZHAW.
E-mail: camerden@students.zhaw.ch
Released under the LaTeX Project Public License v1.3c or later
See http://www.latex-project.org/lppl.txt
----------------------------------------------------------------
\endpreamble
\postamble
Copyright (C) 2019 by Dennis Camera <camerden@students.zhaw.ch>
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License (LPPL), either
version 1.3c of this license or (at your option) any later
version. The latest version of this license is in the file:
http://www.latex-project.org/lppl.txt
This work is "maintained" (as per LPPL maintenance status).
This work consists of the file zhawthesis.dtx
and the derived files zhawthesis.ins,
zhawthesis.pdf and
zhawthesis.cls.
\endpostamble
\usedir{tex/latex/zhawthesis}
\generate{
\file{\jobname.cls}{\from{\jobname.dtx}{class}}
}
%</install>
%<install>\endbatchfile
%<*internal>
\usedir{source/latex/zhawthesis}
\generate{
\file{\jobname.ins}{\from{\jobname.dtx}{install}}
}
\nopreamble\nopostamble
\usedir{doc/latex/zhawthesis}
% XXX: Do not generate README.txt since we already have a README.md in this repository
% \generate{
% \file{README.txt}{\from{\jobname.dtx}{readme}}
% }
\ifx\fmtname\nameofplainTeX
\expandafter\endbatchfile
\else
\expandafter\endgroup
\fi
%</internal>
%<*class>
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{zhawthesis}[2019/02/28 v1.0 Initial version]
%</class>
%<*driver>
\documentclass{ltxdoc}
\usepackage[T1]{fontenc}
\usepackage[numbered]{hypdoc}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\OnlyDescription
\usepackage{microtype}
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
%\GetFileInfo{\jobname.cls}
%
%\title{^^A
% \textsf{zhawthesis} --- ZHAW thesis\thanks{^^A
% This file describes version \fileversion, last revised \filedate.^^A
% }^^A
%}
%\author{^^A
% Dennis Camera\thanks{E-mail: camerden@students.zhaw.ch}^^A
%}
%\date{Released \filedate}
%
%\maketitle
%
%\changes{v1.0}{2019/02/28}{First public release}
%
%\StopEventually{^^A
% \clearpage
% \PrintChanges
% \PrintIndex
%}
%
%\section*{The Code}
% \begin{macrocode}
%<*class>
% \end{macrocode}
%% ========================================================================== %%
%% Thesis class %%
%% ========================================================================== %%
\def\zhaw@babellangde{nswissgerman}
\def\zhaw@babellangen{english}
\newcommand{\zhaw@lang}{de}
\newcommand{\zhaw@babellang}{\zhaw@langde}
\newif\if@german\@germantrue
\newcommand{\zhaw@thesistype}{}
\newcommand{\zhaw@thesistypelong}{}
\DeclareOption{ba}{
\renewcommand{\zhaw@thesistype}{BA}
\renewcommand{\zhaw@thesistypelong}{%
\if@german{Bachelorarbeit}\else{Bachelor thesis}\fi%
}
}
\DeclareOption{pa}{
\renewcommand{\zhaw@thesistype}{PA}
\renewcommand{\zhaw@thesistypelong}{%
\if@german{Projektarbeit}\else{Project work}\fi%
}
}
\DeclareOption{german}{
\@germantrue
\renewcommand{\zhaw@lang}{de}
\renewcommand{\zhaw@babellang}{\zhaw@babellangde}
\PassOptionsToClass{\zhaw@babellang}{scrbook}
}
\DeclareOption{english}{
\@germanfalse
\renewcommand{\zhaw@lang}{en}
\renewcommand{\zhaw@babellang}{\zhaw@babellangen}
\PassOptionsToClass{\zhaw@babellang}{scrbook}
}
% Passes and class options to the underlying article class
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{scrbook}}
\ProcessOptions
\RequirePackage[T1]{fontenc}
\RequirePackage[utf8]{inputenc}
\LoadClass[listof=totoc,bibliography=totoc]{scrbook}
\RequirePackage{microtype}
\RequirePackage{graphicx}
\if@german
\RequirePackage[\zhaw@babellangen,main=\zhaw@babellangde]{babel}
\else
\RequirePackage[\zhaw@babellangde,main=\zhaw@babellangen]{babel}
\fi
\babeltags{de=\zhaw@babellangde,en=\zhaw@babellangen}
\RequirePackage{iflang}
\RequirePackage[autostyle=try,strict=true,german=swiss,english=british]{csquotes}
\RequirePackage[output-decimal-marker={.},group-separator={'}]{siunitx}
\sisetup{detect-all}
% hyperref
\RequirePackage[pdfpagelabels]{hyperref}
\hypersetup{%
unicode,
pdfauthor={\@author},
pdftitle={\@title},
pdfsubject={\zhaw@thesistypelong},
pdfkeywords={Thesis;LaTeX}, % TODO: Complete
pdfcreator={pdfLaTeX},
pdfduplex={DuplexFlipLongEdge},
pdflang={\zhaw@lang},
bookmarksopen,
bookmarksnumbered
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Configure header and footers
\RequirePackage[automark]{scrlayer-scrpage}
\automark[chapter]{chapter}
\clearpairofpagestyles
\lehead{\@title}
\rohead{\@author}
\ofoot[\pagemark]{\pagemark}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ZHAW functions
\newcommand{\zhaw@institute}{}
\providecommand{\zhawinstitute}[1]{\renewcommand{\zhaw@institute}{#1}}
\newcommand{\zhaw@logocolour}{pantone2945}
\providecommand{\zhawlogocolour}[1]{\renewcommand{\zhaw@logocolour}{#1}}
\newcommand{\zhaw@major}{}
\providecommand{\major}[1]{\renewcommand{\zhaw@major}{#1}}
\newcommand{\zhaw@semester}{}
\providecommand{\zhawsemester}[1]{\renewcommand{\zhaw@semester}{#1}}
\newcommand{\zhaw@mainsupervisor}{}
\providecommand{\mainsupervisor}[1]{\renewcommand{\zhaw@mainsupervisor}{#1}}
\newcommand{\zhaw@subsupervisor}{}
\providecommand{\subsupervisor}[1]{\renewcommand{\zhaw@subsupervisor}{#1}}
\newcommand\zhaw@industrypartner{}
\providecommand{\industrypartner}[1]{\renewcommand{\zhaw@industrypartner}{#1}}
\newcommand{\zhaw@extsupervisor}{}
\providecommand{\externalsupervisor}[1]{\renewcommand{\zhaw@extsupervisor}{#1}}
\newcommand{\zhaw@titlepagerow}[2]{%
\begin{minipage}[t]{0.3\textwidth}
\hrule\vskip 5mm
\textbf{#1}
\end{minipage}
% \hskip 0.03\textwidth
\hfil
\begin{minipage}[t]{0.67\textwidth}
\hrule\vskip 5mm
#2 \\
\end{minipage}%
}
\newcommand{\zhaw@maketitlepage}{
\thispagestyle{empty}
\clearpage
\begin{titlepage}
\sffamily
% Logo
\begin{picture}(0,0)
\put(-30,-50){
\includegraphics[width=84.2mm]{logos/zhaw/\zhaw@lang-zhaw-\zhaw@institute-\zhaw@logocolour}
}
\end{picture}
\vskip 10mm
\hskip 26mm
\begin{minipage}[b]{0.91\textwidth}
\vskip 20mm
{\huge
% Projekt Name (max. 2 Zeilen)
\textbf{\underline{{\zhaw@thesistypelong} in {\zhaw@major}}} \\
\textbf{\underline{{\zhaw@semester}}} \\
% Projekt Titel (max. 4 Zeilen)
{
\huge{\@title} \\[1.25ex]
\large{\@subtitle}
}
\vspace{9mm}
}
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Autoren}{Author}}{%
\@author \\
}
\if\zhaw@mainsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Hauptbetreuung}{Main supervisor}}{%
\zhaw@mainsupervisor \\
}
\fi
\if\zhaw@subsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Nebenbetreuung}{Sub supervisor}}{%
\zhaw@subsupervisor \\
}
\fi
\if\zhaw@industrypartner\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Industriepartner}{Industrial partner}}{%
\zhaw@industrypartner \\
}
\fi
\if\zhaw@extsupervisor\empty\else
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Externe Betreuung}{External supervisor}}{%
\zhaw@extsupervisor \\
}
\fi
\zhaw@titlepagerow{\IfLanguageName{nswissgerman}{Datum}{Date}}{%
\@date \\
}
\end{minipage}
\vskip 5mm
\end{titlepage}
}
\renewcommand{\maketitle}{\zhaw@maketitlepage}
\RequirePackage{pdfpages}
\providecommand{\makedeclarationoforiginality}{%
\cleardoublepage%
\if@german%
\includepdf{includes/Erklaerung_Selbstaendigkeit_SoE_\zhaw@thesistype_de.pdf}
\else%
\includepdf{includes/Declaration_of_Originality_SoE_\zhaw@thesistype_en.pdf}
\fi%
}
\AtBeginDocument{%
\pagestyle{scrheadings}
% Set 1st level itemize bullet symbol to --
\def\labelitemi{--}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Functions
% Define math operators
\providecommand\norm[1]{\left\lVert#1\right\rVert}
% \signed{...} function for quote blocks
\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
\hbox{}\nobreak\hfil(#1)%
\parfillskip=0pt \finalhyphendemerits=0 \endgraf}}
% \begin{macrocode}
%</class>
% \end{macrocode}
%\Finale

@ -0,0 +1,69 @@
%%
%% This is file `zhawthesis.ins',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% zhawthesis.dtx (with options: `install')
%% ----------------------------------------------------------------
%% zhawthesis --- A LaTeX class for writing a thesis at ZHAW.
%% E-mail: camerden@students.zhaw.ch
%% Released under the LaTeX Project Public License v1.3c or later
%% See http://www.latex-project.org/lppl.txt
%% ----------------------------------------------------------------
%%
\input docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble
----------------------------------------------------------------
zhawthesis --- A LaTeX class for writing a thesis at ZHAW.
E-mail: camerden@students.zhaw.ch
Released under the LaTeX Project Public License v1.3c or later
See http://www.latex-project.org/lppl.txt
----------------------------------------------------------------
\endpreamble
\postamble
Copyright (C) 2019 by Dennis Camera <camerden@students.zhaw.ch>
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License (LPPL), either
version 1.3c of this license or (at your option) any later
version. The latest version of this license is in the file:
http://www.latex-project.org/lppl.txt
This work is "maintained" (as per LPPL maintenance status).
This work consists of the file zhawthesis.dtx
and the derived files zhawthesis.ins,
zhawthesis.pdf and
zhawthesis.cls.
\endpostamble
\usedir{tex/latex/zhawthesis}
\generate{
\file{\jobname.cls}{\from{\jobname.dtx}{class}}
}
\endbatchfile
%%
%% Copyright (C) 2019 by Dennis Camera <camerden@students.zhaw.ch>
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License (LPPL), either
%% version 1.3c of this license or (at your option) any later
%% version. The latest version of this license is in the file:
%%
%% http://www.latex-project.org/lppl.txt
%%
%% This work is "maintained" (as per LPPL maintenance status).
%%
%% This work consists of the file zhawthesis.dtx
%% and the derived files zhawthesis.ins,
%% zhawthesis.pdf and
%% zhawthesis.cls.
%%
%%
%% End of file `zhawthesis.ins'.

Binary file not shown.

@ -0,0 +1 @@
Subproject commit 0009512345fbd95fe1c745414fffed6c63ccd1aa

@ -0,0 +1 @@
Subproject commit 66c72f095e6da255bde8df6a913815a7dde25665

@ -0,0 +1,14 @@
#!/bin/bash
# Usage example:
# ./count-function.sh ":" "((map)|(fmap))" "((foldr)|(foldl'?))" "filter" \
# "reverse" "take" "drop" "sum" "zip" "product" "maximum" "minimum"
dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "Searching for occurrences in subdirectories of $dir"
for func in "$@"; do
occurrences="$(rg --type hs " $func " --count-matches | awk -F ':' '{sum += $2} END {print sum}')"
echo "Found $occurrences occurrences of \"$func\""
done

@ -0,0 +1 @@
Subproject commit 91f2bcfe73fa3a489654ee74bca02e24423dc5c0

@ -0,0 +1 @@
Subproject commit dea57bd1bec9ba5c4e438de80b2017eee4a30a40

@ -0,0 +1 @@
Subproject commit 183fc22549011804d973e01654e354b728f2bc70

@ -0,0 +1 @@
Subproject commit 124b45d36d7f81e45a9aa3aef588fd5e132fb6fd

@ -0,0 +1 @@
Subproject commit 68a03e05e5e030d7274c712ffa39768310e70f8a

@ -0,0 +1,3 @@
module newbuiltins
go 1.14

@ -0,0 +1,47 @@
package main
import (
"fmt"
"strconv"
)
// Counterpart to Haskell's `derive Show` through code generation
//go:generate stringer -type parity
type parity int
const even parity = 0
const odd parity = 1
// shouldBe returns a function that returns true if an int is
// of the given parity
func shouldBe(p parity) func(i int) bool {
return func(i int) bool {
return i%2 == int(p)
}
}
func main() {
lst := []int{1, 2, 3, 4, 5}
lstMult := fmap(
func(i int) int { return i * 5 },
prepend(0, lst),
)
addToString := func(s string, i int) string {
return s + strconv.Itoa(i) + " "
}
// fold over even / odd numbers and add them to a string
evens := foldl(addToString, even.String()+": ",
filter(shouldBe(even), lstMult))
odds := foldl(addToString, odd.String()+": ",
filter(shouldBe(odd), lstMult))
fmt.Println(evens, odds)
}

@ -0,0 +1,24 @@
// Code generated by "stringer -type parity"; DO NOT EDIT.
package main
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[even-0]
_ = x[odd-1]
}
const _parity_name = "evenodd"
var _parity_index = [...]uint8{0, 4, 7}
func (i parity) String() string {
if i >= parity(len(_parity_index)-1) {
return "parity(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _parity_name[_parity_index[i]:_parity_index[i+1]]
}

@ -0,0 +1,3 @@
module foldl-workaround
go 1.14

@ -0,0 +1,37 @@
package main
import "fmt"
func main() {
zero, one, two, three := 0, 1, 2, 3
list := []*int{&one, &two, nil, &three, &zero}
// this will work, as the values will be evaluated
// "lazily" - the nested functions will never
// be executed, thus it will never panic.
fmt.Printf("%v\n", myFold(mulLazy, 1, list))
// This will panic.
fmt.Printf("%v\n", foldl(mul, 1, list))
}
func mul(x int, y *int) int {
if *y == 0 {
return 0
}
return x * *y
}
func mulLazy(x func() int, y *int) func() int {
return func() int {
if *y == 0 {
return 0
}
return x() * *y
}
}
func myFold(f func(func() int, *int) func() int, acc int, list []*int) int {
a := func() int { return acc }
a = foldl(f, a, list)
return a()
}

@ -0,0 +1,48 @@
package fractran
type fraction struct {
numerator int
denominator int
}
type multResult interface {
multResult()
}
type success int
func (success) multResult() {}
type failure struct{}
func (failure) multResult() {}
func mult(f fraction, n int) multResult {
switch (n * f.numerator) % f.denominator {
case 0:
return success(n * f.numerator / f.denominator)
default:
return failure{}
}
}
type program []fraction
func exec(p program, input int) []int {
var run func([]fraction, []int) []int
run = func(f []fraction, inputs []int) []int {
if len(f) == 0 {
return inputs
}
switch r := mult(f[0], inputs[0]).(type) {
case success:
return run(p, prepend(int(r), inputs))
case failure:
return run(f[1:], inputs)
}
return nil
}
return run(p, []int{input})
}

@ -0,0 +1,26 @@
package fractran
import (
"testing"
)
func TestFractran(t *testing.T) {
p := program{
{91, 33},
{11, 13},
{1, 11},
{399, 34},
{17, 19},
{1, 17},
{2, 7},
{187, 5},
{1, 3},
}
input := 31250
res := exec(p, input)
if res[0] != 8192 {
t.Errorf("did not get correct result. expected=%v, got=%v", 8192, res[0])
}
}

@ -0,0 +1,3 @@
module fractran
go 1.14

@ -0,0 +1,3 @@
module functional-options
go 1.14

@ -0,0 +1,32 @@
package webserver
type Server struct {
Timeout time.Duration
Port int
ListenAddress string
}
type Option func(*Server)
func Timeout(d time.Duration) Option {
return func(s *Server) { s.Timeout = d }
}
func Port(p int) Option {
return func(s *Server) { s.Port = p }
}
func New(opts ...Option) *Server {
s := &Server{ // initialise with default values
Timeout: 500*time.Millisecond,
Port: 0, // uses a random port on the host
ListenAddress: "http://localhost",
}
// apply all options
for _, opt := range opts {
opt(s)
}
return s
}
// usage examples from outside the package:
s := webserver.New() // uses all the default options
s := webserver.New(webserver.Timeout(time.Second), webserver.Port(8080))

@ -0,0 +1,3 @@
module funcsort
go 1.14

@ -0,0 +1,20 @@
package main
import "fmt"
func main() {
fmt.Println(quicksort([]int{1, 8, 5, 3, 4, 9}))
}
// start-quicksort
func quicksort(p []int) []int {
if len(p) == 0 {
return []int{}
}
lesser := filter(func(x int) bool { return p[0] > x }, p[1:])
greater := filter(func(x int) bool { return p[0] <= x }, p[1:])
return append(quicksort(lesser), prepend(p[0], quicksort(greater))...)
}
// end-quicksort

@ -0,0 +1,3 @@
module intlist
go 1.14

@ -0,0 +1,41 @@
package list
func listOps(list []int) {
// collect all elements in a list and increment
// each element by one
var incremented []int
for _, n := range list {
incremented = append(incremented, n+1)
}
// same, but with new builtin
incremented2 := fmap(
func(x int) int { return x + 1 },
list)
// scale each element by factor s
// and add t, collect results in
// new list
s := 2
t := 1
scaled := fmap(
func(x int) int { return s*x + t },
list)
// filter all even elements and
// collect them in a new list
even := filter(
func(x int) bool { return x%2 == 0 },
list)
// sum all elements in the list
sum_reduce := 0
for _, n := range list {
sum_reduce += n
}
// same, but with builtin
sum_reduce2 := foldl(
func(a, b int) int { return a + b },
0, list)
}

@ -0,0 +1,38 @@
public static void listLambdas(List<Integer> list) {
// Sammelt alle Elemente der Liste um 1 inkrementiert
// in einer neuen Liste
List <Integer > incremented = new ArrayList<Integer>();
for(int n : list) {
incremented.add(n+1);
}
// Variante mit Lambdas
List<Integer> incremented2 = list.stream()
.map(x -> x + 1)
.collect(Collectors.toList());
// Skaliert die Element in der Liste um den Faktor s
// und addiert dazu jeweils t;
// sammelt das Ergebnis in einer neuen Liste
final int s = 2;
final int t = 1;
List<Integer> scaled = list.stream()
.map(x -> s * x + t)
.collect(Collectors.toList());
// Filtert alle geraden Elemente aus der Liste
// und sammelt sie in einer neuen Liste
List<Integer> even = list.stream()
.filter(x -> x % 2 == 0)
.collect(Collectors.toList());
// Summiert die Elemente in der Liste
int summe_reduce = 0;
for(int n : list) {
summe_reduce += n;
}
// Variante mit Lambdas
int summe_reduce2 = list.stream()
.reduce(0, (a, b) -> a + b);
}

@ -0,0 +1,3 @@
module mutate
go 1.14

@ -0,0 +1,30 @@
package main
import "fmt"
func main() {
m := MyStruct{
x: "struct",
y: 42,
}
fmt.Println(m) // {struct 42}
mutateNoPointer(m)
fmt.Println(m) // {struct 42}
mutatePointer(&m)
fmt.Println(m) // {changed 0}
}
type MyStruct struct {
x string
y int
}
func mutateNoPointer(m MyStruct) {
m.x = "changed"
m.y = 0
}
func mutatePointer(m *MyStruct) {
m.x = "changed"
m.y = 0
}

@ -0,0 +1,3 @@
module shadowing
go 1.14

@ -0,0 +1,25 @@
package main
import "fmt"
func main() {
x := 5
fmt.Println(x) // 5
// introducing a new scope
{
// this assignment would be forbidden, as it
// overwrites the parent block's value value.
x = 3
fmt.Println(x) // 3
}
fmt.Println(x) // 3
// introducing a new scope
{
// this redeclares the variable x, effectively
// shadowing it. This will not change the parent
// block's variable.
x := 4
fmt.Println(x) // 4
}
fmt.Println(x) // 3
}

@ -0,0 +1,3 @@
module sumtypes
go 1.14

@ -0,0 +1,33 @@
package main
import "fmt"
func main() {
x := get(false)
switch m := x.(type) {
case myInt:
fmt.Printf("Is integer: %v\n", m)
case myString:
fmt.Printf("Is string: %s\n", m)
}
}
func get(b bool) MySumType {
if b {
return myInt(0)
}
return myString("zero")
}
type MySumType interface {
mysumtype()
}
type myInt int
func (m myInt) mysumtype() {}
type myString string
func (m myString) mysumtype() {}

@ -0,0 +1,107 @@
package calendar
import (
"fmt"
"strconv"
)
// this is basically the same as Haskell's "derive Show"
//go:generate stringer -type dayOfWeek
type dayOfWeek int
const (
Sunday dayOfWeek = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
//go:generate stringer -type month
type month int
const (
January month = iota
February
March
April
May
June
July
August
September
October
November
December
)
func next(x dayOfWeek) dayOfWeek {
switch x {
case Saturday: // reset to 0
return Sunday
default:
return dayOfWeek(int(x) + 1)
}
}
func pad(n int) string {
switch {
case n < 10:
return " " + strconv.Itoa(n)
default:
return strconv.Itoa(n)
}
}
const weekHeader = "Su Mo Tu We Th Fr Sa"
func calendarMonth(m month, startDay dayOfWeek, maxDay int) string {
var days func(dayOfWeek, int) string
days = func(d dayOfWeek, n int) string {
switch {
case d == Sunday && n > maxDay:
return "\n"
case n > maxDay:
return "\n\n"
case d == Saturday:
return pad(n) + "\n" + days(Sunday, n+1)
default:
return pad(n) + " " + days(next(d), n+1)
}
}
// spaces is used to add the initial padding in every month,
// depending on the starting day
var spaces func(dayOfWeek) string
spaces = func(currDay dayOfWeek) string {
switch currDay {
case startDay:
return days(startDay, 1)
default:
return " " + spaces(next(currDay))
}
}
return fmt.Sprintf("%v 2020\n%v\n%v", m, weekHeader, spaces(Sunday))
}
func Calendar() {
year := calendarMonth(January, Wednesday, 31) +
calendarMonth(February, Saturday, 29) +
calendarMonth(March, Sunday, 31) +
calendarMonth(April, Wednesday, 30) +
calendarMonth(May, Friday, 31) +
calendarMonth(June, Monday, 30) +
calendarMonth(July, Wednesday, 31) +
calendarMonth(August, Saturday, 31) +
calendarMonth(September, Tuesday, 30) +
calendarMonth(October, Thursday, 31) +
calendarMonth(November, Sunday, 30) +
calendarMonth(December, Tuesday, 31)
fmt.Println(year)
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save