You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
So @Qata was asking about a potential roadmap for Juniper 5.0.0. I thought I'd put together a features list for a potential future release.
Typeclasses
Including support for higher kinded polymorphism (ex: Functor), functional dependencies, and multiple parameters. Currently Juniper has support for a number of built-in typeclasses, primarily the numerical types and record types. Take for example the add function from the Prelude module:
fun add(numA : a, numB : a) : a where a : num = numA + numB
In this case num is actually a single parameter typeclass.
For records, Juniper also currently has a typeclass like implementation. For example:
fun example(arg : a) where a : { x : int32, y : b } = ...
We have an autogenerated two parameter typeclass HasX, whose first parameter is the type of the record (in this case a) and the second parameter is the type of the field. The equivalent notation in Haskell for this example would be something like HasX a int32 => .... Note that for HasY, the Haskell notation is HasY a b => .... Since b is uniquely determined by a, we need functional dependencies to properly constrain the function signature.
The difficulty with implementing this feature is high, and will require updates to the parser, type checker, type inferencer, and the transpiler (that is, conversion to C++). The transpiler portion should be easy, as C++ already supports overloaded functions, and has its own take on typeclasses called concepts. We should consider looking into also outputting concepts in the C++ code for extra safety.
I suspect that the main difficulty will come in the type inference and checker portion - especially when checking for things like overlapping instance and managing superclasses.
The syntax I am thinking of is something like this:
typeclass Functor<f> {
fun fmap((a) -> b, f<a>) : f<b>
fun (<$)(a, f<b>) : f<a>
}
instance Functor<linkedlist> {
fun fmap(f, llst) = ...
}
Another interesting thing to do with typeclasses is implement an iter function to be used in conjunction with for in loops. This would allow generic iteration over a variety of different datatypes. We could also consider using typeclasses to provide access to the built in square bracket [] member access: mylist[x] or myhashmap[x]
For the numeric typeclasses, my preference is to combine both the Haskell approach and the Purescript approach. The main arithmetic operations are implemented as part of a Field typeclass, and then separate typeclasses for num, int and real. For example,
// Num typeclass will likely be built in, maybe we cannot create custom instances
// Note that all instances of Num must also be instances of Field
typeclass Num<a> where Field<a> { }
instance Num<int32> { }
instance Num<float> { }
This allows for numerical literals to be polymorphic, while keeping the algebraic benefits of fields.
Recursive datatypes
Currently Juniper does not allow for recursive datatypes. We could add a special annotation for recursive datatypes, which also implies that any values of this type will be stored on the heap. For example:
type rec linkedlist<a> = cons(a, linkedlist<a>) | nil()
Note that without mutable references or tying the knot (ie, with Haskell laziness), it is not possible to create a reference cycle. Since this is the case we can adopt the existing reference counting system. I therefore think that this feature will be slightly less difficult than the typeclass feature.
We will of course want to track any uses of the ref type, and judiciously outlaw their use where they could lead to reference cycles.
Difficulties: there will be a lot of different array/list datatypes: the current array and list implementation, the new linked list implementation, and potentially an array implementation whose size can be set at runtime. Also, should we have special syntax sugar for constructing linked lists? Currently we have array literals, but if we have N different list types, should we have special syntax for all of them?
Pattern Match Exhaustiveness
This is a pretty critical feature for ensuring that programs don't crash. We should definitely have the compiler emit a warning in the cases where pattern matching is not exhaustive.
I would like to move from a single level module system to a system more like C++ namespaces. Modules currently in the standard library can be moved to the std namespace, Arduino specific things can be moved to std:Arduino, for example std:Arduino:Io. There are lots of places right now that assume that a module is defined by a single name, so changing this will require adjusting lots of things in the compiler. Not a technically complicated project, but will still require a lot of effort.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
So @Qata was asking about a potential roadmap for Juniper 5.0.0. I thought I'd put together a features list for a potential future release.
Typeclasses
Including support for higher kinded polymorphism (ex: Functor), functional dependencies, and multiple parameters. Currently Juniper has support for a number of built-in typeclasses, primarily the numerical types and record types. Take for example the
add
function from the Prelude module:In this case
num
is actually a single parameter typeclass.For records, Juniper also currently has a typeclass like implementation. For example:
We have an autogenerated two parameter typeclass
HasX
, whose first parameter is the type of the record (in this casea
) and the second parameter is the type of the field. The equivalent notation in Haskell for this example would be something likeHasX a int32 => ...
. Note that forHasY
, the Haskell notation isHasY a b => ...
. Sinceb
is uniquely determined bya
, we need functional dependencies to properly constrain the function signature.The difficulty with implementing this feature is high, and will require updates to the parser, type checker, type inferencer, and the transpiler (that is, conversion to C++). The transpiler portion should be easy, as C++ already supports overloaded functions, and has its own take on typeclasses called concepts. We should consider looking into also outputting concepts in the C++ code for extra safety.
I suspect that the main difficulty will come in the type inference and checker portion - especially when checking for things like overlapping instance and managing superclasses.
The syntax I am thinking of is something like this:
Another interesting thing to do with typeclasses is implement an
iter
function to be used in conjunction withfor in
loops. This would allow generic iteration over a variety of different datatypes. We could also consider using typeclasses to provide access to the built in square bracket[]
member access:mylist[x]
ormyhashmap[x]
For the numeric typeclasses, my preference is to combine both the Haskell approach and the Purescript approach. The main arithmetic operations are implemented as part of a Field typeclass, and then separate typeclasses for
num
,int
andreal
. For example,This allows for numerical literals to be polymorphic, while keeping the algebraic benefits of fields.
Recursive datatypes
Currently Juniper does not allow for recursive datatypes. We could add a special annotation for recursive datatypes, which also implies that any values of this type will be stored on the heap. For example:
Note that without mutable references or tying the knot (ie, with Haskell laziness), it is not possible to create a reference cycle. Since this is the case we can adopt the existing reference counting system. I therefore think that this feature will be slightly less difficult than the typeclass feature.
We will of course want to track any uses of the
ref
type, and judiciously outlaw their use where they could lead to reference cycles.Difficulties: there will be a lot of different array/list datatypes: the current array and list implementation, the new linked list implementation, and potentially an array implementation whose size can be set at runtime. Also, should we have special syntax sugar for constructing linked lists? Currently we have array literals, but if we have N different list types, should we have special syntax for all of them?
Pattern Match Exhaustiveness
This is a pretty critical feature for ensuring that programs don't crash. We should definitely have the compiler emit a warning in the cases where pattern matching is not exhaustive.
See issue #12
Support for nested modules/namespaces
I would like to move from a single level module system to a system more like C++ namespaces. Modules currently in the standard library can be moved to the
std
namespace, Arduino specific things can be moved tostd:Arduino
, for examplestd:Arduino:Io
. There are lots of places right now that assume that a module is defined by a single name, so changing this will require adjusting lots of things in the compiler. Not a technically complicated project, but will still require a lot of effort.Beta Was this translation helpful? Give feedback.
All reactions