Initial import.
This commit is contained in:
5
uc/hs/ChangeLog.md
Normal file
5
uc/hs/ChangeLog.md
Normal 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
20
uc/hs/LICENSE
Normal 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
2
uc/hs/Setup.hs
Normal file
@@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
BIN
uc/hs/images/meaning_simple_semantics.png
Normal file
BIN
uc/hs/images/meaning_simple_semantics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 526 KiB |
228
uc/hs/src/Meaning.lhs
Normal file
228
uc/hs/src/Meaning.lhs
Normal 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 × 4»
|
||||
```
|
||||
|
||||
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 × 4»
|
||||
*Meaning> otherExpression
|
||||
«1 × 2 + 3 × 4»
|
||||
```
|
||||
|
||||
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 × 4»
|
||||
*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 × 4»
|
||||
*Meaning> reduce otherExpression
|
||||
«1 × 5 × 4»
|
||||
```
|
||||
|
||||
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 × 4»
|
||||
*Meaning> run anMachine
|
||||
EXP ← «1 × 2 + 3 × 4»
|
||||
EXP ← «2 + 3 × 4»
|
||||
EXP ← «2 + 12»
|
||||
EXP ← «14»
|
||||
EXP ← «14»
|
||||
```
|
||||
67
uc/hs/uc.cabal
Normal file
67
uc/hs/uc.cabal
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user