Initial import.

This commit is contained in:
2018-01-16 09:46:44 -08:00
commit 36ed6df77f
29 changed files with 1035 additions and 0 deletions

5
uc/hs/ChangeLog.md Normal file
View File

@@ -0,0 +1,5 @@
# Revision history for uc
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

20
uc/hs/LICENSE Normal file
View File

@@ -0,0 +1,20 @@
Copyright (c) 2016 Kyle Isom
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2
uc/hs/Setup.hs Normal file
View File

@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

228
uc/hs/src/Meaning.lhs Normal file
View File

@@ -0,0 +1,228 @@
Chapter 2: The Meaning of Programs
==================================
> module Meaning where
Programming is about ideas, not about the programs themselves;
they're manifestations (sometimes even physical) of someone's ideas;
there must be some *raison d'être* for program to be written. That
reason can be to scratch an itch, but some motivation needs to drive
the program.
Linguistics has a field called *semantics*, which "is the study of
the connection between words and their meanings;" computer science
has *formal semantics*, which deals with specifying these connections
mathemtically (more or less). Specifying a programming language
requires both a syntax (*how does the program look*?) and semantics
(*what does the program mean*?). Funny enough, many (most?) PL's
don't have some canonical formal specification, relying on
"specification by implementation."
Syntax
------
Remember: syntax = how does the program look?
Programming is currently done largely as text files, which are
really just long strings of characters where newlines give the
appearance of some structure. We fead this string into a parser of
some sort, which knows the language's syntax rules. The parser takes
the string and converts into an *abstract syntax tree*, which is
the computer's representation of the program in memory. **N.B.**:
parsers are covered later.
Syntax provides a mechanism for the meaning of a program to be
expressed, but it doesn't have any deeper meaning. The connection
is entirely arbitrary, though there are common patterns that have
arisen (c.f. the C-style of langauges).
Operational Semantics
---------------------
"The most practical way to think about the meaning of a program is
*what it does*." That is, what happens when it runs? I really liked
how Tom phrased it: "How do different constructs in the programming
language behave at run time, and what effect do they have when
they're plugged together to make larger programs?"
*Operational semantics* defines rules for how programs execute,
typically on an *abstract machine*, allowing for more precise
specifications of a language's behaviour.
Small-Step Semantics
--------------------
How do we go about designing an abstract machine? A first step is
to think about how a program that works by reduction on the syntax.
For example, evaluating (1 × 2) + (3 × 4):
1. First, the leftmost expression is reduced: × is applied to 1
and 2. This leaves us with 2 + (3 × 4).
2. The rightmost expression is reduced: × is applied to 3
and 4. This leaves us with 2 + 12.
3. Finally, + is applied to 2 and 12, yielding 14.
4. 14 can't be reduced any further, so this is taken as the result
of the expression. This is a *value*, which has a standalone
meaning.
The rules for these reductions need to be codified in their own
*metalanguage*. To explore the semantics of a very simple programming
language called SIMPLE.
[ insert meaning_simple_semantics.png here ]
These are *inference rules* defining a *reduction relation* on
SIMPLE ASTs. "Practically speaking, it's a bunch of weird symbols
that don't say anything intelligible about the meaning of computer
programs." Time to dive into an implementation!
Tom is careful to note that this isn't an attempt at specification
by implementation; it's making the description more approachable
for readers without a mathematical background.
Expressions
-----------
We can start by defining some types for the different elements ofthe AST.
> data Element = Number Int |
> Boolean Bool |
> Add Element Element |
> Multiply Element Element |
> LessThan Element Element |
> Equals Element Element |
> GreaterThan Element Element
For convenience, we'll override show. In the book, SIMPLE ASTs are
displayed inside «».
> -- strElement returns the string representation of an AST element.
> strElement :: Element -> String
> strElement (Number n) = show n
> strElement (Boolean b) = show b
> strElement (Add a b) = (strElement a) ++ " + " ++ (strElement b)
> strElement (Multiply a b) = (strElement a) ++ " × " ++ (strElement b)
> -- showElement implements show for Element.
> showElement :: Element -> String
> showElement e = "«" ++ (strElement e) ++ "»"
> instance Show Element where show = showElement
These elements can be strung together to hand-build an AST:
> anExpression = Add (Multiply (Number 1) (Number 2))
> (Multiply (Number 3) (Number 4))
This *should* display as
```
Ok, modules loaded: Meaning.
*Meaning>
*Meaning> anExpression
«1 × 2 + 3 ×
```
Note that this doesn't take into account operator precedence, so
`anExpression` is the same as `otherExpression` defined below:
> otherExpression = Multiply (Number 1)
> (Multiply (Add (Number 2) (Number 3))
> (Number 4))
With proper precendence, this should be `1 * (2 + 3) * 4`, but note
```
*Meaning> anExpression
«1 × 2 + 3 ×
*Meaning> otherExpression
«1 × 2 + 3 ×
```
This is a problem, but it's not relevant to the discussion of the
semantics of SIMPLE.
Now we need to implement a reducer. First, let's determine if an
expression *can* be reduced:
> -- reducible returns true if the expression is reducible.
> reducible :: Element -> Bool
> reducible (Number _) = False
> reducible _ = True
> -- reduce reduces the expression.
> reduce :: Element -> Element
> reduce n@(Number _) = n
> reduce (Add (Number a) (Number b)) = Number (a + b)
> reduce (Add a b) = if (reducible a)
> then (Add (reduce a) b)
> else (Add a (reduce b))
> reduce (Multiply (Number a) (Number b)) = Number (a * b)
> reduce (Multiply a b) = if (reducible a)
> then (Multiply (reduce a) b)
> else (Multiply a (reduce b))
Using `reduce` right now means repeatedly running `reduce` over
functions:
```
*Meaning> reduce anExpression
«2 + 3 ×
*Meaning> reduce (reduce anExpression)
«2 + 12»
*Meaning> reduce (reduce (reduce anExpression))
«14»
```
Note that `reduce` returns different expressions for `anExpression`
and `otherExpression`, which demonstrates that the string display
issue is tangential to our semantics:
```
*Meaning> reduce anExpression
«2 + 3 ×
*Meaning> reduce otherExpression
«1 × 5 ×
```
Let's abstract this into a machine; note that this won't work quite
like the Ruby examples in the book, as we can't really keep state
in Haskell.
> -- Machine abstracts the SIMPLE VM.
> data Machine = Machine Element
> instance Show Machine where
> show (Machine e) = "EXP ← " ++ (show e)
We can define two functions on it: `step` and `run`:
> -- step runs a single reduction.
> step :: Machine -> Machine
> step (Machine e) = Machine (reduce e)
> -- run keeps calling step until a non-reducible expression is
> -- found.
> run :: Machine -> IO Machine
> run m@(Machine e) = do
> putStrLn (show m)
> if (reducible e)
> then run (step m)
> else return (Machine e)
Let's try this with `anExpression`:
> anMachine = Machine anExpression
```
*Meaning> step anMachine
EXP ← «2 + 3 ×
*Meaning> run anMachine
EXP ← «1 × 2 + 3 ×
EXP ← «2 + 3 ×
EXP ← «2 + 12»
EXP ← «14»
EXP ← «14»
```

67
uc/hs/uc.cabal Normal file
View File

@@ -0,0 +1,67 @@
-- Initial uc.cabal generated by cabal init. For further documentation,
-- see http://haskell.org/cabal/users-guide/
-- The name of the package.
name: uc
-- The package version. See the Haskell package versioning policy (PVP)
-- for standards guiding when and how versions should be incremented.
-- https://wiki.haskell.org/Package_versioning_policy
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0
-- A short (one-line) description of the package.
synopsis: Literate Haskell explorations from the book 'Understanding Computation'.
-- A longer description of the package.
-- description:
-- The license under which the package is released.
license: MIT
-- The file containing the license text.
license-file: LICENSE
-- The package author(s).
author: Kyle Isom
-- An email address to which users can send suggestions, bug reports, and
-- patches.
maintainer: kyle@imap.cc
-- A copyright notice.
-- copyright:
category: Meta
build-type: Simple
-- Extra files to be distributed with the package, such as examples or a
-- README.
extra-source-files: ChangeLog.md
-- Constraint on the version of Cabal needed to build this package.
cabal-version: >=1.10
library
-- Modules exported by the library.
-- exposed-modules:
-- Modules included in this library but not exported.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
-- Other library packages from which modules are imported.
build-depends: base >=4.9 && <4.10
-- Directories containing source files.
hs-source-dirs: src
-- Base language which the package is written in.
default-language: Haskell2010