Flix language handles effects nicely (only purity, it seems here): https://flix.dev/#/blog/taming-impurity-with-polymorphic-effects/
(But I don't like the effects syntax much, I think a nicer syntax could be invented. The semantics seems OK to me).
Flix language handles effects nicely (only purity, it seems here): https://flix.dev/#/blog/taming-impurity-with-polymorphic-effects/
(But I don't like the effects syntax much, I think a nicer syntax could be invented. The semantics seems OK to me).
This sounds like a generalization of "rethrowing" annotations of exceptions from certain languages (I have the most experience with Swift), and it seems more principled than those; on the surface it's even kind of neat.
However, I've found that in practice, polymorphism over effects quickly becomes painful and redundant in the setting of higher-order functions. To elaborate on that:
h
taking a functional argument f
f
may or may not be effectfulh
to match that of f
h
will not be usable with an effectful f
.
f
unusable by a non-polymorphic h
or result in a high number of purity violation false positives.)I've written about this problem in more detail previously: one, two.
I suppose I have trouble accepting that there is even a notion of something being default here when it comes to higher-order functions, because pure/impure/polymorphic all appear to be distinct syntactic categories.
with the examples showing f: Unit -> Unit
being an alias for f: Unit -> Unit & Pure
, and f: Unit ~> Unit
being an alias for f:Unit -> Unit & Impure
, and f: Unit -> Unit & _
presumably being polymorphic, that is the choice between Pure, Impure, and Polymorphic is in all 3 cases explicit (again in this case that is dealing with higher-order functions).
painful, sure but I don't really see how any of the 3 distinct things could redundant.
Probably worth mentioning that pre-1.0 Rust used to have purity annotations like this, but ended up abandoning them because of exactly this problem forcing everyone to opt into "impurity" everywhere and making the annotation meaningless.
They give an example with even two different input functions, f and g:
def mapCompose(f: a -> b & e1, g: b -> c & {{(not e1) / e2}}, xs: List[a]): ... = ...
I'm aware that this is not an unavoidable law, it's "only" the common case. That there are other, less frequent cases doesn't matter, because the baggage and the frustration associated with the common case still remains.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.