Haskell Exchange 22
Haskell Exchange 22
December 2022
Tim’s vision of the metaverse
Social interaction in a shared real-time 3D simulation
An open economy with rules but no corporate overlord
A creation platform open to all programmers, artists, and
designers, not a walled garden
Much more than a collection of separately compiled, statically-
linked apps: everyone’s code and content must interoperate
dynamically, with live updates of running code
Pervasive open standards. Not just Unreal, but any other
game/simulation engine e.g. Unity.
Like the metaverse vision, Verse itself is open
We will publish papers, specification for anyone to implement
We will offer compiler, verifier, runtime under permissive
open-source license with no IP encumbrances.
And …
Learnable as a first language (c.f. Javascript yes, C++ no)
Extensible: mechanisms for the language to grow over time, without
breaking code.
❑ Verse 1: a familiar FP subset
❑ Verse 2: choice
❑ Verse 3: functional logic
Verse is a functional logic language (like Curry or Mercury).
Verse is a declarative language: a variable names a single
value, not a cell whose value changes over time.
Verse is lenient but not strict:
Like strict:, everything gets evaluated in the end
Like lazy: functions can be called before the argument has a value
Verse has an unusual static type system: types are first-
class values.
Verse has an effect system, rather than using monads.
A subset of Verse is a fairly ordinary functional language
Integers 3 3+7
x:=3; x+x
For now, think
“letrec-binding”
x:=3; y:=x+1; x*y
Order does
not matter
Arguments on
the LHS…
f:=(x:int=>x+1); f(3)
Conditionals
Recursion
A Haskell expression denotes one value
A Verse expression denotes a sequence of zero or more values
3 One value
A quirky notation
3 | 4 Two values for “fail”
Choice
operator false? Zero values
Returns e1 if e succeeds
“Succeeds” = returns one or more values
Returns e2 if e fails
“Fails” = returns zero values
if (x<20) then e1 else e2
(x<20)
fails if x >= 20
succeeds if x < 20, returning the left operand
Example: (3 + (x<20))
Succeeds if x=7, returning 10
Fails if x=25
“If x is 2 or 3 then…”
if (x=(2|3)) then e1 else e2
= (1,4,9)
for e1 do e2
Form the N-tuple from the
Iterate over the N (non-failing)
value(s) of range e2
choices in the domain e1 (variables bound in e1 scope over e2)
= (1,2,3) | (1,2,10) |
(1,9,3) | (1,9,10) |
..
And we can use that
choice to iterate:
xs is successively bound to all
xs := for(1..5) do (0|1|2); ...xs...
5-digit numbers in base 3
for e1 do e2
Form the N-tuple from the
Iterate over the N (non-failing)
value(s) of range e2
choices in the domain e1 (variables bound in e1 scope over e2)
= false?
for e1 do e2
Form the N-tuple from the
Iterate over the N (non-failing)
value(s) of range e2
choices in the domain e1 (variables bound in e1 scope over e2)
= (2*2, 4*4)
= (4,16)
1..n is (1 | 2 | ... | n)
as:=(3,7,4);
for{i:int; as[i]+1}
What values can i take? Clearly just 0,1,2!
So expand as[i] to those three choices
This is called “narrowing” in the functional logic literature
as:=(3,7,4); as:=(3,7,4);
for{i:int; as[i] + 1} = for{i:int; ((i=0; 3+1) |
(i=1; 7+1) |
(i=2; 4+1)) }
By the way,
Bring x into
x must be 7
scope.
(or else fail) The very same
I’m not telling
you what its “=” as before
value is yet
Think:
x:=7; x+1>3; y=x*2 • “:” brings the variable
into scope.
• Scope extends to the
means the same as left as well as right
x+1>3; y=(x:=7)*2
Haskell let (y,z) = if (x=0) then (3,4)
else (232, 913)
in y+z
w:tuple(int,int);
swap(w) = (3,4); Run swap “backward”: Also returns (4,3)
w
What does this do? x:int; y:int;
if (x=0) then y=1 else y=2;
x=7;
Sets the value y
Reads the
of x Sets the
value of x
value of y
Analogy:
MaxVerse = Haskell
CoreVerse = Lambda calculus
“=” is a language construct, not a primop (like gt)
<v1,..,vn> for tuples to avoid ambiguity with (x)
“x” is what we previously wrote “x:ty” (except I’m not telling you about types)
fail is a language construct, alongside “|”
Core Verse is untyped (like lambda calculus)
x:tuple(int,int);
x = (2,y:int);
x. x = (y. <2,y>);
x = (z:int,3); Desugar x = (z. <z,3>);
x x
Main constructs
exists brings a variable into scope
unification = says that two expressions have the same value
sequencing ; sequences unifications
choice |, fail
conditional one return first success
for-loops all return all successes
x. x = (y. <2,y>);
x = (z. <z,3>);
x
In this example:
x=<2,3>, z=2, y=3
Operationally: unification.
But unification is hard for programmers
backtracking, choice points, undoing, rigid variables, …
foo x = x*x + 1
25 + 1
5*5 + 1
26
To answer "what does this program do, or what does it mean?“
just apply the rewrite rules
Rewrite rules are things like
Add/multiply constants
Replace a function call with a copy of the function's RHS, making substitutions
Substitute for a let-binding
Substitute for
(one occurrence of) x
x:tuple(int,int);
x = (2,y:int);
x. x = (y. ⟨2,y⟩);
x = (z:int,3); Desugar x = (z. ⟨z,3⟩);
x x
Decompose equality
of pairs (unification)
x:tuple(int,int);
x = (2,y:int);
x. x = (y. ⟨2,y〉);
x = (z:int,3); Desugar x = (z. ⟨z,3〉);
x x
Verse is open
Open spec, open-source compiler, published papers (I hope!)