Skip to content
Snippets Groups Projects
Commit ed4bb9ee authored by Lou Knauer's avatar Lou Knauer
Browse files

README.md, renamend stuff in lib/stdlib.rb, bug in concatMap was circumvented by that

parent 7a781285
Branches
Tags
No related merge requests found
# Ruby-Implementation of a Dhall-like Language
If you want to use *Dhall* in production and do not use *ruby*, use the official haskell version linked below.
- Dhall github project: https://github.com/dhall-lang
- Treetop library's home page: http://cjheath.github.io/treetop/index.html
See `./tests` for an example of dhallish-code that should work. `.dhall`-files show code that
evaluates equally in `dhall` and `dhallish`. Code samples in `./tests/test.rb` might be dhallish-specific.
See `./bin/dhallish` for an example on how to use the `Dhallish` module.
See `./bin/dhallish` or `./tests/test_dhallish_ctx.rb` for an example on how to use the `Dhallish` module.
*Read [the docs](./DOCS.md)!*
```bash
# run tests using:
ruby ./tests/test.rb
# use dhall as a command line tool:
./bin/dhallish --help
./bin/dhallish <<< "1 + 2"
# examples and usage:
cat ./tests/examples.dhallish
./bin/dhallish --help
./bin/dhallish < texts/examples.dhallish
```
### Changes to `dhall-lang`:
- More Operators: `<`, `>`, `<=`, `>=`, `-`, `/`
- `==` and `!=` do work on Numbers (`Natural`s, `Integer`s and `Double`s)
- It is possible to get an Optional from an union
### Missing Features:
- [x] Optionals
- [x] Records
- [x] Functions
- [x] Imports
- [x] `env:...`
- [ ] Stuff we are not thinking of right now...
- Unions (not planed)
## TODO
- [ ] disallow Type Names like `Natural` or `let` as labels
- [ ] more tests and tests for expected failure
- [ ] "n-1": currently interpreted as label, but should be a subtraction (sometimes)
- [ ] Bignums for Integers?
- [ ] Multi Line strings
- [ ] quoted labels
- [ ] MORE UNICODE!
- `''strings that start with two quotes''`
### Known Bugs:
- There is a bug in our unification or substitution that only appears in rare cases when the same name for a generic type is used multiple times.
......@@ -3,13 +3,17 @@ require_relative './utils.rb'
module Dhallish
# Utility function to create dhallish function types:
# Use [:name] to introduce a new unresolved type and write
# :name to use it. Look at `fill_context` for examples.
def make_fn_type(*args, rettype)
if Types::not_a_type?(rettype); rettype = Types::Unresolved.new(rettype) end
args.reverse.reduce(rettype) { |rettype, arg|
argtype = arg
name = nil
if arg.is_a? Array
argtype, name = arg
name = arg[0]
argtype = Types::Type.new(Types::Unresolved.new(name))
end
if Types::not_a_type?(argtype); argtype = Types::Unresolved.new(argtype) end
Types::Function.new(argtype, rettype, name)
......@@ -74,9 +78,9 @@ module Dhallish
# Lists:
globalctx["List"] = BuiltinFunction.new { |a| Types::List.new(a) }
types["List"] = make_fn_type([Types::Type.new, :a], Types::Type.new(Types::List.new(Types::Unresolved.new(:a))))
types["List"] = make_fn_type([:list_a], Types::Type.new(Types::List.new(Types::Unresolved.new(:list_a))))
list_length_type = make_fn_type([Types::Type.new(Types::Unresolved.new(:a)), :a], Types::List.new(Types::Unresolved.new(:a)), Types::Natural)
list_length_type = make_fn_type([:list_len_a], Types::List.new(Types::Unresolved.new(:list_len_a)), Types::Natural)
globalctx["List/length"] = BuiltinFunction.new{ |a|
BuiltinFunction.new { |list|
list.length
......@@ -85,11 +89,11 @@ module Dhallish
types["List/length"] = list_length_type
list_fold_type = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
[Types::Type.new(Types::Unresolved.new(:b)), :b],
make_fn_type(:a, :b, :b),
:b, :b)
[:list_fold_a],
Types::List.new(Types::Unresolved.new(:list_fold_a)),
[:list_fold_b],
make_fn_type(:list_fold_a, :list_fold_b, :list_fold_b),
:list_fold_b, :list_fold_b)
globalctx["List/fold"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list|
BuiltinFunction.new { |b|
......@@ -104,9 +108,9 @@ module Dhallish
types["List/fold"] = list_fold_type
list_head_type = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
Types::Optional.new(Types::Unresolved.new(:a)))
[:list_head_a],
Types::List.new(Types::Unresolved.new(:list_head_a)),
Types::Optional.new(Types::Unresolved.new(:list_head_a)))
globalctx["List/head"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list|
list.first
......@@ -115,9 +119,9 @@ module Dhallish
types["List/head"] = list_head_type
list_last_type = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
Types::Optional.new(Types::Unresolved.new(:a)))
[:list_last_a],
Types::List.new(Types::Unresolved.new(:list_last_a)),
Types::Optional.new(Types::Unresolved.new(:list_last_a)))
globalctx["List/last"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list|
list.last
......@@ -126,9 +130,9 @@ module Dhallish
types["List/last"] = list_last_type
list_tail_type = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
Types::List.new(Types::Unresolved.new(:a)))
[:list_tail_a],
Types::List.new(Types::Unresolved.new(:list_tail_a)),
Types::List.new(Types::Unresolved.new(:list_tail_a)))
globalctx["List/tail"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list|
if list.empty?
......@@ -141,19 +145,19 @@ module Dhallish
types["List/tail"] = list_tail_type
types["List/reverse"] = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
Types::List.new(Types::Unresolved.new(:a)))
[:list_reverse_a],
Types::List.new(Types::Unresolved.new(:list_reverse_a)),
Types::List.new(Types::Unresolved.new(:list_reverse_a)))
globalctx["List/reverse"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list| list.reverse }
}
types["List/build"] = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
[:list_build_a],
make_fn_type(
[Types::Type.new(Types::Unresolved.new(:b)), :b],
make_fn_type(:a, :b, :b), :b, :b),
Types::List.new(Types::Unresolved.new(:a)))
[:list_build_b],
make_fn_type(:list_build_a, :list_build_b, :list_build_b), :list_build_b, :list_build_b),
Types::List.new(Types::Unresolved.new(:list_build_a)))
globalctx["List/build"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |f|
cons = BuiltinFunction.new { |x|
......@@ -164,11 +168,11 @@ module Dhallish
}
types["List/indexed"] = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::List.new(Types::Unresolved.new(:a)),
[:list_indexed_a],
Types::List.new(Types::Unresolved.new(:list_indexed_a)),
Types::List.new(Types::Record.new({
"index" => Types::Natural,
"value" => Types::Unresolved.new(:a)})))
"value" => Types::Unresolved.new(:list_indexed_a)})))
globalctx["List/indexed"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |list|
list.map.with_index { |val, idx|
......@@ -181,14 +185,14 @@ module Dhallish
globalctx["Optional"] = BuiltinFunction.new { |a|
Types::Optional.new(a)
}
types["Optional"] = make_fn_type([Types::Type.new, :a], Types::Type.new(Types::Optional.new(Types::Unresolved.new(:a))))
types["Optional"] = make_fn_type([:opt_a], Types::Type.new(Types::Optional.new(Types::Unresolved.new(:opt_a))))
optional_fold_type = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
Types::Optional.new(Types::Unresolved.new(:a)),
[Types::Type.new(Types::Unresolved.new(:b)), :b],
make_fn_type(:a, :b),
:b, :b)
[:opt_fold_a],
Types::Optional.new(Types::Unresolved.new(:opt_fold_a)),
[:opt_fold_b],
make_fn_type(:opt_fold_a, :opt_fold_b),
:opt_fold_b, :opt_fold_b)
globalctx["Optional/fold"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |opt|
BuiltinFunction.new { |b|
......@@ -207,10 +211,10 @@ module Dhallish
types["Optional/fold"] = optional_fold_type
types["Optional/build"] = make_fn_type(
[Types::Type.new(Types::Unresolved.new(:a)), :a],
make_fn_type([Types::Type.new(Types::Unresolved.new(:b)), :b],
make_fn_type(:a, :b), :b, :b),
Types::Optional.new(Types::Unresolved.new(:a)))
[:opt_build_a],
make_fn_type([:opt_build_b],
make_fn_type(:opt_build_a, :opt_build_b), :opt_build_b, :opt_build_b),
Types::Optional.new(Types::Unresolved.new(:opt_build_a)))
globalctx["Optional/build"] = BuiltinFunction.new { |a|
BuiltinFunction.new { |f|
just = BuiltinFunction.new { |x| x }
......@@ -222,9 +226,9 @@ module Dhallish
# Naturals:
natural_fold_type = make_fn_type(
Types::Natural,
[Types::Type.new(Types::Unresolved.new(:a)), :a],
make_fn_type(:a, :a),
:a, :a)
[:nat_fold_a],
make_fn_type(:nat_fold_a, :nat_fold_a),
:nat_fold_a, :nat_fold_a)
globalctx["Natural/fold"] = BuiltinFunction.new { |n|
BuiltinFunction.new { |a|
BuiltinFunction.new { |succ|
......@@ -252,7 +256,7 @@ module Dhallish
succ = BuiltinFunction.new { |n| n + 1 }
f.call(Types::Natural).call(succ).call(zero)
}
types["Natural/build"] = make_fn_type(make_fn_type([Types::Type.new(Types::Unresolved.new(:a)), :a], make_fn_type(:a, :a), :a, :a), Types::Natural)
types["Natural/build"] = make_fn_type(make_fn_type([:nat_build_a], make_fn_type(:nat_build_a, :nat_build_a), :nat_build_a, :nat_build_a), Types::Natural)
end
module_function :fill_context
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment