-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdesign
86 lines (73 loc) · 4.36 KB
/
design
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
solar - i saw the summer sun in the fullness of its glory
i wrote a thing about how Lua is just Hoon but with by-reference and mutable variables
i really like this framing
i've wanted to make "hoon but different" for a while, so instead of using its weird
syntax use lua-ish syntax
- purely functional
- first-class contexts (getfenv(0), basically, with no upvalues/locals)
- statically strongly typed
- functions are objects are cores - balls of state with computed properties, closed over an environment. arguments are implemented as variables closed over and set before computing the "body" property.
- ocaml has "object types" which are structurally typed records of methods
- can we have a function that takes _[ add = fn(@ *@) ] and destructure objects
at the callsite? does this play well with captures?
- casting wouldn't be "view only", but constructing new values:
foo = [ a = 1 b = 2 c = 3 ] bar = [ a = 3 c = 4 ] `_bar`foo
now the cast has to allocate. is this ok? "new" casting method, like ^-?
- does this let you do Monad interfaces?
- cons cores don't work
- function overloading: instead of mul calling add that needs @ -> @, have
a way to register how to construct an "atom core"? rust's Into/From.
would be very "magic", ruin structural subtyping. just have a function that
wraps a value in a core, call manually.
- really due to broken symmetry of nouns/cells. cells should be last resort
for state machines/interfaces, but "add" and "mul" are useful interfaces too
- have a method for (mostly) type-safe replacing arms!!! impossible to replace
++add with your own impl. we have type information for the entire context
by definition, should be able to rewrite all closed cores with new impl
- how does this work with core co/contravariance? doesn't, tbh.
- can cheat and just redefine at VM level for methods,
same "result not implementation" as nock
- the dream is to be able to mock just via context replacement, which
doesnt quite work in hoon. you can't extend open:ut without
copy-pasting all arms. would this help? retypecheck resulting core?
roadmap:
- cores
- functions (jets?)
- recursion, holds
- "eval with changes"
- fishing, flow dependent typing
- type-level functions
- variance
problems:
- think about ast -> type -> nock more
- more ast nodes for reductions? let -> within?
- cores recursive typechecking - hold?
- generics and function specialization. collections not being able to use the same function names is pretty bad. snag vs get:in vs get:by. structural subtyping means that there's no clear pick for what impl to even choose.
- monads and hkt. continuations with no call stack.
hey kids wanna make a compiler lol
ended up dumping rust code ('''tulpa''') and rewrote everything in lua in like 1/3rd the time with 1/3 the length
making a compiler in lua sounds like one of those things that makes you say "dont do that you moron" but lets do it anyways
there's llvm lua bindings! they looks surprisingly good! wtf! it even has api support for jit!
i forgot how annoying lpeg was though so ill write the parser later - just hardcode asts for now
how do we typecheck recursive functions?
here is `add`, which is represented as core with an arm `$` and [a=0 b=0 .] context
|= {a/@ b/@}
?: =(b 0)
a
$(a +(a), b (dec b))
naive will just typecheck infinitely: typing `$` will require you to type `$`
infinite loops have type `!!` aka void, which is bottom
forks between any value and void is just the value
type then becomes fork(@, type_ast($ with changes)), detect loop, fork(@ !!), @.
is there anything this doesn't work for? mutually recursive functions?
`=< a =+ foo=0 |% ++ a ?~ foo a(foo [1 2]) foo --` will actually give you "failed to compute type" for hoon!
checked - recursive functions actually just leave %holds for the recursive calls without collapsing to void,
and then nest/fish/cast evaluate the holds later. is this nessacary? in practice doesn't matter since
recursive functions always come with a typecast?
what about `gulf`, which builds lists from a to b?
|= {a/@ b/@}
?: =(a +(b))
~
[a $(a +(a))]
just bubbling up a void would type this as `$~`, which isn't enough - you could transmute it into a (list ^) and break stuff.
hoon types this as `#1.?($~ {@ #1})` - either `$~` or an atom cons with something.