]> git.rmz.io Git - my-scheme.git/log
my-scheme.git
7 years agoUse `showVal` to print with show rather than the default master
Samir Benmendil [Tue, 23 Jan 2018 22:49:41 +0000 (22:49 +0000)]
Use `showVal` to print with show rather than the default

Inject `showVal` as the `show` member of an instance of `Show LispVal`.

7 years agoShow values for Lists
Samir Benmendil [Tue, 23 Jan 2018 22:46:38 +0000 (22:46 +0000)]
Show values for Lists

`unwordsList :: [LispVal] -> String` composes three functions:
* `map :: (a -> b) -> [a] -> [b]` a function with two "arguments"[0], a
  function `(a -> b)` and a list of `a`s (`[a]`) and returns a `[b]`, i.e.
  it applies the function in the first argument to every element of the
  second
* `showAll :: LispVal -> String` described in the previous commit.
  `map showAll` returns a function that applies `showAll` to each
  element of the list it gets.
* `unwords :: [String] -> String` which joins a list of Strings with
  spaces.

The `.` dot operator is used to pass the output of rhs to the input of
lhs. So in essence, `unwordsList` is a function that will `unword` the
list of Strings returned by `map`ing `showVal` to the list of `LispVal`s
passed to `unwordsList`.

[0] Remember that all functions are curried, and actually only take one
argument and return a "partial function" that takes the next argument.

7 years agoShow values (except Lists)
Samir Benmendil [Tue, 23 Jan 2018 22:27:16 +0000 (22:27 +0000)]
Show values (except Lists)

We introduce a `showVal :: LispVal -> String` function, to turn a
LispVal into a printable string.

This function uses pattern matching to "specialize" on various types.
The declaration that matches the specific type is chosen.

7 years agoAdd parsers for List, DottedList and Quoted
Samir Benmendil [Tue, 23 Jan 2018 20:39:54 +0000 (20:39 +0000)]
Add parsers for List, DottedList and Quoted

Nothing really new here.

7 years agoAdd Character parser
Samir Benmendil [Sun, 21 Jan 2018 12:06:07 +0000 (12:06 +0000)]
Add Character parser

Refactor `nonPrintableChar` into its own Parser type to be reused in
`parseCharacter` and `parseString`

7 years agoSupport #bodx in number parser
Samir Benmendil [Sun, 21 Jan 2018 00:56:01 +0000 (00:56 +0000)]
Support #bodx in number parser

`where radix = ...` returns a function that takes a number and parses it
accordingly. The function is chosed by 'try'ing to read a '#' followed
by any of "bodx" and if that fails assume the base is decimal.

The `>>` sequencing operator is used to combine `char` and `oneOf`, they
are executed one after another, discarding the value of the first.

`readInt` takes a base (2), a predicate returning what chars are valid
and a function that describes the Integer value for a char.
`(\x -> elem x "01")` is a lambda that returns true if x is in "01".

`(read . (:[]))` is interesting. The `.` operator composes the functions
`read` and `:[]`, where `:` is the append to list function and `[]` is
the "first argument", i.e. `:[]` appends an element to the empty list.

`let ((a,_):_) = ...` extracts the number from the `[(Number,String)]`
type returned by the `read*` functions.

Because strings starting with '#' are valid Atoms as well, we need to
parse for numbers first.

7 years agoAdd various escape chars
Samir Benmendil [Sat, 20 Jan 2018 22:41:50 +0000 (22:41 +0000)]
Add various escape chars

7 years agoSupport escaped quotes
Samir Benmendil [Sat, 20 Jan 2018 22:32:20 +0000 (22:32 +0000)]
Support escaped quotes

`innerChar` matches a char that is not a backslash or a quote. If it is
either, it will match a backslash, capture a following quote and lift a
quote char into the `innerChar` monad.

This will not support anything other than quote after the backslash char.

7 years agoUsing where for parsing inner characters
Samir Benmendil [Sat, 20 Jan 2018 22:22:42 +0000 (22:22 +0000)]
Using where for parsing inner characters

This should make it somewhat easier to add more parsers and support
'\"', '\n', etc

7 years agoTail recursing main function
Samir Benmendil [Sat, 20 Jan 2018 22:14:23 +0000 (22:14 +0000)]
Tail recursing main function

Infinite Read Evaluate Print Loop (REPL)

Don't know if this is how this should work.

7 years ago`deriving` from `Show` is a really easy way to print values
Samir Benmendil [Sat, 20 Jan 2018 22:12:51 +0000 (22:12 +0000)]
`deriving` from `Show` is a really easy way to print values

Probably only works for type that can already be shown.

7 years agoUse do block again
Samir Benmendil [Sun, 14 Jan 2018 16:55:52 +0000 (16:55 +0000)]
Use do block again

This is much better

7 years agoUsing the "bind" operator
Samir Benmendil [Sun, 14 Jan 2018 16:55:02 +0000 (16:55 +0000)]
Using the "bind" operator

The `do..` block seems easier

7 years agoUse do to parse numbers
Samir Benmendil [Sun, 14 Jan 2018 16:26:47 +0000 (16:26 +0000)]
Use do to parse numbers

This is not necessarily better than the `liftM` method (probably isn't).

7 years agoParse expressions (string, atom or number)
Samir Benmendil [Sun, 14 Jan 2018 00:46:22 +0000 (00:46 +0000)]
Parse expressions (string, atom or number)

Nothing new here.

7 years agoParse Numbers
Samir Benmendil [Sun, 14 Jan 2018 00:41:31 +0000 (00:41 +0000)]
Parse Numbers

`many1 digit` matches one or more digits. But it's result is actually a
`Parser String`. We need a way to operate on the value inside the `Parser
String` monad. This is where `liftM` comes in.

Another new thing here is the `.` operator which applies the function on
the right to any input of the function on the left. Or in other words it
applies the right function and passes the result to the function on the
left. In this case, `read` is applied to the parsed digits and the
result (of type Integer) is passed to the `Number` constructor of
`LispVal`.

7 years agoHandle boolean constants
Samir Benmendil [Sun, 14 Jan 2018 00:24:21 +0000 (00:24 +0000)]
Handle boolean constants

Turns out that Scheme defines `#t` and `#f` to be `true` and `false`.

`let` is used to devife a new symbol `atom` which is a String.
`case...of` matches the literals and constructs a `LispVal` of the
appropriate type and value. `_` is a match all token.

7 years agoParse Atoms which start with a letter or symbol
Samir Benmendil [Sun, 14 Jan 2018 00:19:18 +0000 (00:19 +0000)]
Parse Atoms which start with a letter or symbol

`<|>` is a Parser combinator, the choice operator. It will try the first
parser, if it doesn't match anything, try the second parser, and so on.

`a:b` creates a list from `a` and `b`. Another possibility would be to
use `[a] ++ b`, where a new list with a single element is created `[a]`
and concatenated with `++`

7 years agoParse Strings surrounded by `"`
Samir Benmendil [Sun, 14 Jan 2018 00:03:01 +0000 (00:03 +0000)]
Parse Strings surrounded by `"`

We need to use a `do-block` because we would like to keep the return
value of a parse in the middle. So we parse a single `char '"'`, parse
`many (noneOf "\"")` and assign the return value to `x` and parse
another `"`.

We apply the `String` constructor to the value of `x` to turn it into a
`LispVal` with `String x`.

Finally we inject the `LispVal` into the `Parser` monad. We need to do
this because each line of a `do-block` needs to be of the same type but
the result of `String x` is a `LispVal`, not a `Parser`. `return` wraps
the `LispVal` up in a `Parser` action that consumes no input.

Consider `a $ b c` as syntactic sugar for `a (b c)`.

7 years agoAdd LispVal data type which can hold any Lisp value
Samir Benmendil [Sat, 13 Jan 2018 23:40:49 +0000 (23:40 +0000)]
Add LispVal data type which can hold any Lisp value

LispVal is an algebraic type which is able to hold any of the types
given.

Not sure what the type of `DottedList` is meant to be.

7 years agoIgnore spaces
Samir Benmendil [Sat, 13 Jan 2018 23:24:30 +0000 (23:24 +0000)]
Ignore spaces

We add the spaces `Parser` which returns nothing `()` and skips any
spaces.

`spaces` is already defined in Parsec, but does not do exactly what we
want, we can hide it from the import.

`skipMany a` matches 0 or more `a` and skips them.

`>>` is the **bind** operator. It may have completely different meanings
depending on the monad you use. In the Parser monad in means "try the
first parameter, then try the second with anything that is left", i.e.
"first skip all the spaces, then match the symbol".

7 years agoreadExpr function to check whether the input matches symbol
Samir Benmendil [Sat, 13 Jan 2018 23:05:55 +0000 (23:05 +0000)]
readExpr function to check whether the input matches symbol

`readExpr :: String -> String` defines `readExpr` to be a function
(`->`) from String to a String.

`readExpr input = ...` will assign anything on the rhs to the `readExpr`
function where `input` is mapped to the first parameter of that
function.

`case ... of` is a *filter*.

`parse a b c` is a function from Parsec where `a` is the parser it should
use, `b` is the name of the input which is used for error messages and
`c` is the String to parse.

`parse` returns an `Either` type whose `Left` constructor indicates an
error. If we get a `Right` value, we bind it to `val`, ignore it and
return the String "Found Value".

7 years agoDefine a parser for various symbols in Scheme
Samir Benmendil [Sat, 13 Jan 2018 22:41:38 +0000 (22:41 +0000)]
Define a parser for various symbols in Scheme

`symbol :: Parser Char` is probably not needed (?)

I don't understand where the `Parser` type comes from, I cannot see it
in the doc of `Text.ParserCombinators.Parsec`. It may be that
`ParserCombinators` is a compatibility layer and that `Parser` is
defined somewhere else.

`oneOf` is provided by Parsec.

7 years agoImport the Parsec library
Samir Benmendil [Sat, 13 Jan 2018 22:24:47 +0000 (22:24 +0000)]
Import the Parsec library

If we want to use the new library, it needs to be imported.

More info for the library can be found on GitHub.
https://github.com/haskell/parsec

7 years agoAdd Parsec dependencie
Samir Benmendil [Sat, 13 Jan 2018 22:22:28 +0000 (22:22 +0000)]
Add Parsec dependencie

This is a Parser module that will be used in the project.

`stack` makes it quite easy to add dependencies. Simply change the
`dependencies` list in `package.yaml` and run `stack build` again. Any
missing modules will be installed.

7 years agoReading input from stdin
Samir Benmendil [Sat, 13 Jan 2018 22:07:28 +0000 (22:07 +0000)]
Reading input from stdin

Introducing `getLine` which reads the next line from stdin.

7 years agoPrint the sum of two arguments
Samir Benmendil [Sat, 13 Jan 2018 22:06:26 +0000 (22:06 +0000)]
Print the sum of two arguments

`read`'s type is defined as `read :: (Read a) => String -> a`, i.e.
`read` takes as `String` and returns an `a` (number?). I don't know what
`=>` means. (`(Read a)` is an instance of class Read ?)

`show`'s type is a bit more complicated it seems as it has multiple
instances for various types of input. But in essence it takes a type and
returns a `String`.

7 years agoRead two arguments from commandline
Samir Benmendil [Sat, 13 Jan 2018 21:59:14 +0000 (21:59 +0000)]
Read two arguments from commandline

`!!` is the "list indexing" operator. It returns the value in the list
on the lhs at the index on the rhs.

`++` concatenates two lists.

A string is a list of chars.

7 years agoHello World with argument
Samir Benmendil [Sat, 13 Jan 2018 21:56:06 +0000 (21:56 +0000)]
Hello World with argument

This will simply print "Hello, " followed by the first argument from the
commandline.

Every Haskell program needs to have a main "action" in the Main module.
This is the entry point.

Files starting with `module <Foo>` will be part of the `Foo` module.

By convention modules are capitalized and definitions aren't.

`import System.Environment` provides `getArgs` to access cli arguments.

Haskell is strongly typed and types may be assigned with `::`. In this case
`main` is of type `IO ()` which is an IO action holding no information.
(more on that later hopefully, as I don't fully understand that.)

7 years agoNew project
Samir Benmendil [Sat, 13 Jan 2018 21:28:41 +0000 (21:28 +0000)]
New project

This project was generated by `stack new`. Some files are obviously not
in use yet, or simply wrong.

7 years agoRoot Commit
Samir Benmendil [Sat, 13 Jan 2018 20:45:07 +0000 (20:45 +0000)]
Root Commit