* add sketch for drop
* add drop example
* correct drop ordering
* fix: simplify drop and add to deleter
* docs: add drop docs
* fix: use a sound lifetime var
* feat: a proper dynamic numeric tower
The following things were changed and/or added:
- `Dynamic.neg` was added
- `Dynamic.mod` was changed to work on float values
- `Dynamic.cxr` was changed to work with `0` instructions
- `Dynamic.=` was changed to ignore the type of the number
- `Dynamic.round` was added
- dynamic arithmetic was changed to respect the numeric type tower
- the instances of `Eq` and `Ord` for `Number` are no longer derived, so that they work across numeric types
- the instance of `Num` for `Number` was changed to work across numeric types
- `promoteNumber` was added as a type function to implement the numeric tower.
The numeric tower is as follows:
Byte -> Int -> Long -> Float -> Double
* test: add tests for cxr, neg, and =
* test: add tests for Dynamic.round
* fix: make set! work with dynamic args (thanks @hellerve)
Like `let` before it, we used to bind function arguments to their values
only, which wasn't accounted for in `set!` such that one could not
`set!` `i` in `defndynamic [i] ...`. To fix this for let bindings we
introduced a `LetDef` form for consistency with Def forms. This commit
renames `LetDef` to `LocalDef` and uses it as a value for function
arguments in addition to let bindings, ensuring `set!` works on function
arguments too. Big thanks to @hellerve for the suggestion!
* test: add regression test for set! on dynamic function args
* feat: quasiquotation
* test: add tests for quasiquotation
* fix: fix typo in call to doc
* fix: do not evaluate quasiquote too eagerly
* test: pull quasiquote test into macro
* docs: fix unquote example with better constant
* feat: add quasiquote literals
* refactor: simplify reader macros
* core: add derive
* fix: fix errors with set!
Notably, don't type check dynamic bindings (which can be set to
whatever) and eliminate a hang that resulted from not handling an error
at the end of the `set!` call. Also refactors some of the code in
efforts to make it a bit cleaner.
Also adds an error when `set!` can't find the variable one calls set!
on.
* feat: better derive
* test: add error test for derive
* document derive
* add derive to core documentation to generate
* core: add derive
* fix: fix errors with set!
Notably, don't type check dynamic bindings (which can be set to
whatever) and eliminate a hang that resulted from not handling an error
at the end of the `set!` call. Also refactors some of the code in
efforts to make it a bit cleaner.
Also adds an error when `set!` can't find the variable one calls set!
on.
* feat: better derive
* document derive
* feat: first completely working version of derive
* feat: make name of derivable customizable (thanks @scolsen)
* refactor: implement doc edits provided by @scolsen
* feat: change argument order for derive
* fix: change deriver error test
* test: add derive tests
* fix: change order of derive back
* docs: fix typo in derive document
Co-authored-by: scottolsen <scg.olsen@gmail.com>
* feat: add semigroup instance for Env and Context
Adds a semigroup instance for combining Envs and Contexts--this will be
necessary to ensure closure's are evaluated under the combination of the
context captured in the closure and the current global context during
evaluation.
The semigroup instances are left biased and will prefer bindings defined
in the left context/env argument in the case of conflicts (this is in
keeping with the implementation of `union` in Data.Map, the underlying
function powering this instance).
* fix: evaluate closures under the current context
Previously, closures were evaluated only under the context that was
stored during their creation. However, this can lead to issues where
closures do not resolve bindings to their latest definitions.
This commit leverages the semigroup instance of Context to evaluate
closures under the combination of the context captured during their
creation and the broader context during their evaluation/application,
preferring the context captured in the closure when bindings conflict.
This ensures that when we apply closures their local bindings still
resolve to definitions encapsulated in the closure, while other bindings
resolve to the definitions contained in the current overarching context
(instead of the old context captured by the closure).
* fix: fix bias for context env combinations in semigroup
Previously, the semigroup instance for Context was left-biased in all
the combinations of each context's environment. However, one usually
calls this function to combine some older context with a newer context,
intending to have the older context win *only* in the case of internal
environments.
This commit changes the behavior of the semigroup instance to better
reflect this use case. When one calls:
`c <> c'`
The envs in each context are combined as follows:
- internal: If conflicts occur, prefer the bindings of the context on
the LHS (the "older" context)
- global: If conflicts occur, prefer the bindings of the context on the
RHS ("newer" context)
- type: If conflicts occur, prefer the bindings of the context on the
RHS ("newer" context)
This ensures the resulting context uses the latest values in the chance
of conflicts in the global env/type env, and the older values in the
case of an internal env (a closure).
* test: add basic tests for closures
* refactor: rename test/closure -> test/dynamic-closure
Also updates the forms to test dynamic closures.
Previously, we couldn't replace qualified bindings in Envs. This change
updates envReplaceBindings to accept qualified paths and to replace the
binding denoted by the path, updating the module environments the binder
belongs to accordingly.
If the qualified path does not denote an existing module, it simply
returns the environment as is (just like the unqualified case).
* fix: account for interfaces in function lookups
An older version of Carp only allowed users to implement interfaces by
defining a function of the same name. Since PR 769 and roughly commit
040e9e4 however, this was no longer the case, since we added a primitive
for implementing interfaces, allowing users to implement interfaces
using functions with whatever name they want.
When this happened, the function lookups that happen during
concretization were never updated to reflect the fact that interface
implementations might have different names than their corresponding
interfaces. It's rare, but this can lead to errors for template
functions in the compiler.
For example, registered types automatically get an implementation of
`prn` with the same name. This function takes a ref to the registered
type as an argument. If a user wants to use such a type as an array
member however, they must provide a prn that takes a value argument
instead of a ref. If the user still wants to keep the ref variant handy,
however, they need to give this new prn implementation a different name,
otherwise Carp will think they are redefining the existing function.
However, using an arbitrary name would result in this second prn
instance not being found during the lookup fixed in this commit, since
it did not match the name of the interface exactly.
After this commit, this issue will no longer crop up, as the
concretize.hs function lookup now accounts for the fact that, if the
function it is looking for is an interface, it may need to find
functions with names that differ from the name it received as an
argument; e.g. a lookup for `prn` could result in finding a function
named `foo` that is a valid implementation of `prn`.
* fix: include interface name in concretize lookup
* refactor: rename allFunctionsWithNameAndSignature
This function now finds implementations of interfaces as well, which
might have a different name than the function name passed as an
argument. This commit renames the function to reflect this; I've also
added some explanatory notes.
A misplaced type env reference caused a bug in which types could not be
placed in modules more than a single level deep. Similarly, existing
modules in the type env were always overwritten when new types were
added to modules that were not disjoint. This commit fixes both issues.
In the future, we should likely make module management functions more
general and call them to manage modules in both the value and type envs.
Notably, don't type check dynamic bindings (which can be set to
whatever) and eliminate a hang that resulted from not handling an error
at the end of the `set!` call. Also refactors some of the code in
efforts to make it a bit cleaner.
Also adds an error when `set!` can't find the variable one calls set!
on.
* feat: overwrite existing interface implementations
This commit alters the behavior of interfaces so that implementations
with the same type signature will overwrite previous implementations
with that signature--before this was a runtime error.
Previously, if a user defined two distinctly named implementations of an
interface that shared a type, Carp would panic and error at runtime if
the interface was called and resolved to the type, since it couldn't
decide which implementation to use from the type alone. After this
commit, we instead issue a warning and overwrite existing
implementations of the same type, so that defining:
```
(defn foo [] 0)
(implements zero foo)
```
will replace `Int.zero` in the `zero` interface's implementation path
list and won't result in a runtime error--instead `foo` will be called
when `zero` is called in a context in which it returns an int:
```
[WARNING] An implementation of the interface zero with type (Fn [] Int)
already exists: Int.zero. It will be replaced by the implementation:
foo.
This may break a bunch of upstream code!
```
test/interface.carp also has a concrete illustration of this case.
* chore: address hlint suggestions
* fix: don't print overridden interface implementations in info
This commit updates our handling of interface overrides to remove
interfaces from the implements meta of a function that was overridden by
a new implementation.
Similarly, this refactors primitiveInfo to prevent printing binders that
do not actually implement an interface.
* refactor: incorporate @TimDeve's error message suggestion