Open chtenb opened 1 month ago
Ha, good catch. Mm, I think it was done this way as I was considering having a different datatype for the while
family of actions:
type while<a>
Continue
Break( result : a )
but I didn't follow up on this. It does feel a bit weird to look for an element in a list with foreach-while
, like
[1,2,3].find-maybe(fn(i) if (i>=3) then Just(i) else Nothing)
vs
[1,2,3].foreach-while(fn(i) if (i>=3) then Break(i) else Continue)
not sure.
Interesting. The Break
/Continue
vocabulary is very charming.
What are your thoughts on having different isomorphic types in the core library, like maybe
and while
?
So continuing on your example, the foreach-while
function would then return a while<a>
value.
Suppose I would like to transform it to an a
value by supplying some default value, I would want to call the fun default( m : maybe<a>, nothing : a ) : a
on it. However, that function is defined for maybe
types, not for while
types.
We could duplicate all functions on maybe
to work for while
values, but that has a clear downside in code complexity.
Why do want to distinguish between isomorphic types at all? I think because we like to use this in domain modelling, such that code becomes more readable, and to make it more difficult to make mistakes related to mixing up values that conceptually represent different things. One could argue that the core library does not do domain modelling, but exists to provide a programmer with a good set of basic operations. To this end, interoperability (i.e. making things possible) is perhaps more important than segmentation (i.e. forbidding things).
On the other hand, perhaps it's not a big deal, as long as there exist conversion functions between isomorphic types?
It does feel a bit weird to look for an element in a list with foreach-while
This is probably different for everyone. For me that was a natural way of using it. I was looking through the module for an iteration function that would allow some form of conditionality, such that I could pick a first element that would satisfy a condition. Something with while
in the name sounds familiar and logical to reach for. It was only later that I found the find-maybe
version and noticed that it did the same thing.
I also think that foreach-while
sounds more general than find-maybe
.
However, that function is defined for
maybe
types, not forwhile
types. We could duplicate all functions onmaybe
to work forwhile
values, but that has a clear downside in code complexity.
FWIW, I would say fun while/maybe(a: while<a>): maybe<a>
solves this problem much more compactly.
Yes, that is what I alluded to in the last sentence. But note that if maybe
is the canonical representation of its isomorphism class, and all the utility functions are defined on maybe
, you will always have to call this conversion function to do something with the result of foreach-while
, save explicit pattern matching.
It would be interesting to have functional inheritance as a feature of datatypes.
i.e.
type maybe<a>
....
type while<a> inheriting (while/maybe)
Continue
Break( result : a )
fun while/maybe(a: while<a>): maybe<a>
...
Essentially the idea is, first implicit resolution attempts to find based on while, and then if it cannot find it, also tries maybe using the implicit coercion. Coercions could be automatically generated for isomorphic types (by request).
I think we can remove find-maybe from the standard library?