-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
monotonously-increasing maps #168
Comments
Hmm, if we want multiple top-level declarations to contribute to the same |
Ah, it works if it's |
The feature is inspired by MetaPRL's "Resources" feature, which is not monotonously-increasing, but does allow attaching values other than definitions to symbols. |
@doyougnu and I discussed possible APIs. Here is the "top-level" approach:
And here is the "macro monad" approach:
We ended up with this hybrid approach:
|
The top-level approach is similar to our existing top-level binders, so let's review how those work. Currently, when we write
The task which expands Similarly, in
The
Thus, the top-level approach is not a good API for MonoMap. |
Another reason why the top-level approach is undesirable is that it does not support some of the use cases we have in mind for MonoMaps. Haskell-style type classes is one such use case, of course, but we also want to allow the user to implement variants of type classes which don't quite match Haskell's design. For example, maybe the user wants to allow a local instance in a where clause which is only visible locally. It seems plausible to use scope sets to restrict the visibility of an instance to a local scope even though the instance is added to a global MonoMap. But with the top-level approach, it would not be possible for a macro in a where clause, deeply nested inside an expression context, to generate a define-mono-map call which is only intended to work in a top-level definition context. |
With the macro-effect approach, it is easier to imagine a pair of macros being expanded in parallel, one being stuck on a call However, one difficulty is that once a parent macro has called Hence our preference for the hybrid approach: a globally-defined MonoMap, accessible by all later macros including the pair of macros we have imagined. Even better: a parent macro can now use such a MonoMap to pass on arbitrary opaque values to later macros! The keys of a MonoMap are identifiers, and identifiers can be passed from a parent macro to a later macro, thus the parent can store an opaque value in a MonoMap, and the later macro can retrieve it from that same MonoMap. |
To implement new types of declarations, such as type classes (#167) or base functors (#162), macros need to be able to cooperate by adding information to some global list or map, in the same way
define
adds entries to the list of top-level definitions.The obvious way to do that is to define a global mutable
Map
and for the macros to mutate it, but allowing macros to perform arbitrary mutations would definitely break Klister's promise that the macros cannot observe the order in which the compiler chooses to expand them.The proposed solution is to take inspiration from the lvish library:
modify (lub x)
for somex
.{x,y,z}
of values which pairwiselub
to ⊤.t
which is ≥ one or more of the valuesx
,y
andz
in our threshold.t ≥ x
andt ≥ y
, thent ≥ lub x y = ⊤
, thust = ⊤
.t
is above exactly one value in the threshold, and that's the value which the threshold read returns.Klister is not using threads, but the goal that the result should not depend on the order in which the tasks are performed is similar to the goal that the result should not depend on the thread scheduling.
If
a
andb
are types with suitable lattices, thenMap k a
,(a, b)
, andEither a b
have suitable latices too. Infinite combinations of these, like[a]
, as well. At the leaves,Set c
andIVar c
(whose lattice haslub c1 c2 = ⊤
for every pair, and thus can only be written to once) have lattices for everyc
. And of course()
andVoid
.So this is quite a rich set of types, and it's not too clear exactly how to provide all of this to the user. But as the very first step, a
Map Symbol (IVar c)
would allow users to create custom top-level definitions by assigning a value to the symbol being defined. The threshold read in this case is simply to wait until a given symbol has been assigned a value, at which point that value is read.The text was updated successfully, but these errors were encountered: