-
Notifications
You must be signed in to change notification settings - Fork 167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Array programming #544
Comments
Actually, they have immutable semantics, but they do update in-place if the vector is unique.
sets index I don't think that there is any issue with our API for vectors and it should be able to do everything you want to do. However, performance might not be competitive with C++ (but likely still be good enough for your needs). We want to improve two performance aspects in the future:
I implemented a graph theory algorithm using the |
@anfelor Additionally while the documentation says map uses a Also, I didn't realize that the In general mutable variables are currently not very performant, due to needing to keep a reference / immutable copy around in case the mutation on the right hand side could use a ctl effect. We should investigate a variant of mutable variable assignment where the rhs is restricted to linear effects so that we can use vectors (embedded in other objects - like vlist) performantly, instead of only supporting 'destructive' vector assignment on the local variable vectors. |
(Edit: I hadn't had a chance to read TimWhiting's response before writing this) Hey @anfelor, thanks for your response!
I would be interested in understanding how compiler is able to infer that this can be done in place, at a high level what is the reasoning it employs? I will probably wait until the morning to test out the quicksort code, but that use of the word "immutable" is somewhat surprising to me. I was not aware of the destructive update operator you mention, it is not mentioned in the sample code supplied with the VSCode plugin (I grepped for it just now) and it is not in the vector file in the stdlib - https://koka-lang.github.io/koka/doc/std_core_vector.html - maybe it would be good to add it to one or both of these? (I will also point out that when I read the phrase "immutable vector", my first reaction is definitely not "This probably has a destructive update operator, and if I search through the documentation long enough, I will find it", which is another reason to mention it prominently.) It sounds like by "immutable" you mean something like, there is a guarantee of no aliasing. So in the code
the array I am not sure I understand the reasoning behind referring to this as
in Futhark (https://futhark-lang.org/blog/2022-06-13-uniqueness-types.html) Is this roughly correct? |
By destructive updates and immutability, we mean the following (@anfelor correct me if I'm wrong):
results in
Or at least that should be the behavior. Unfortunately I think it is not the case due to #522? |
Thank you, this is clear. Further, in this documentation: It is my subjective opinion that "immutable, and supporting destructive update" is a contradiction in terms, and a better term would be something like "vectors providing a no-aliasing guarantee", or "alias-free vectors", because to me mutation and destructive update / destructive assignment are synonymous. I speculate that there are enough others who interpret the words the same way I do to cause confusion. However, I will not press the point if you insist on the term "immutable." |
Thanks for checking, @TimWhiting! I wonder if we should rewrite the function to use in-place updates?
Does that apply here? If I remember correctly,
@patrick-nicodemus, as Tim pointed out above, I wrongly assumed the function would use in-place update when the implementation does not support this yet.
Yes, exactly!
Thanks! That's a great explanation.
Did you encounter an issue here? On my machine, your code returns:
which is what I would have expected. I don't understand why the last output line is duplicated in your output. |
@anfelor As far as the example code, I had simplified it after pasting it: The following snippet was the original, which is why the last line of the output was duplicated. I was trying to demonstrate that often we want to use
In fact I think this is precisely the problem I was trying to illustrate:
The problem is that at the point of call to It also looks like we have a different potential issue with the observability of destructive updates (to all local variables):
This outputs:
Which as you can see shows the mutation to This is what I think @patrick-nicodemus was trying to get at: when he said there is a contradiction between: "immutable, and supporting destructive update". However, I'd push back that it isn't the vectors that are providing destructive update by themselves, it is the fact that they are using local variables which provide non-transactional state effect semantics. And also, just because the effect for local state uses non-transactional state semantics doesn't mean that it isn't "pure" or "immutable", as illustrated by the state and exn handler combination in Koka's book: https://koka-lang.github.io/koka/doc/book.html#sec-combine. All it means is that local vars have chosen an ordering for composing state and surrounding handlers which provides non-transactional semantics. |
We should, but due to the effect issue, we really need a way to qualify a polymorphic effect variable to be linear. I know Daan has a paper about that he did with Jonathan Brachthäuser: https://www.microsoft.com/en-us/research/publication/qualified-effect-types/, but I don't see the ability to do that in the current Koka codebase. We could make a variant of map which is total, but that really restricts the kinds of things you can do. (Especially if you cannot dereference other local variables). |
Yes, that is right. You would have to write something like:
for some
Hmm, I agree that this behavior could be counter-intuitive, but for me the output is exactly what I would have expected. Conceptually, the
Ah, I think they are? Similar to how constructors can be reused, we could have a function
I don't think that you need to make this restriction. What do you think of this implementation:
This prints:
|
For multiple resumptions it makes sense that it would end up copying, but always filling the vector completely. However, I don't think that is safe for all effects. If the function Good point about the default value (your implementation example would need a default value to allow for fip values as well). However, the default value still suffers from the fact that an exception could cause you to lose the old value in the vector and not have a new value either. So it isn't just a temporary value, it is actually changing the semantics, even if you restrict the map function to return the same type. Unfortunately although the runtime does set a flag if it is yielding for a final ctl operation, we don't know that until the rhs is actually yielding and after we have assigned a default value. Even then the operation clause could choose to only conditionally resume. It needs to be guaranteed in the type system to always resume (though I guess it could resume multiple times like you state). |
Sorry, I meant that currently they do not. |
By this I meant that there is not an equivalent way to express this in pure Koka + effects. |
Yes, I agree that this is a terrible hack. But I think this is safe: If you throw an exception and throw the partially overwritten vector away, the runtime immediately calls |
True, I guess the only way it mutates is if it is unique, so it's not really a drop, it is a free. |
Given this discussion I think we need to do the following:
If you need a vector to be mutable and a reference stored to it from a variety of datastructures (reference count would be > 1), that is precisely where a Anything else, or is this all that is needed to address this issue @patrick-nicodemus? As far as mutable variables and transactional / versus non-transactional semantics, that should probably go in a different issue. Maybe we could have another local variable definition form for that: |
We can already do this if we are happy to be less type-safe: Just define
|
Daan actually already has a |
@TimWhiting I think that sounds good to me but I'm not qualified to comment on precisely what should be implented here so if you change your mind later due to some reevaluation of the proper semantics then so be it. My main request is that whatever features are implemented are properly documented, as I said before the destructive update for vectors is not currently documented. |
@anfelor Hi, sorry if this would be best left to a different issue, but you said
First, can you clarify whether this means that all vectors are vectors of "boxed" elements rather than "unboxed" values, and your comment to "cache usage" is referring to this additional dereferencing step? Second, when you say "this would be a major change... we don't currently have the bandwidth" would it be a more feasible/realistic goal to do what OCaml does and introduce a dedicated array type of unboxed floats of a certain precision, the (Edit: apparently the distinction between floatarrays and Bigarrays in OCaml is that floatarrays live on the OCaml runtime heap and Bigarrays live in the C heap, floatarrays are more performant in OCaml code that rapidly allocates/deallocates them, according to this forum discussion - |
Yes and yes. The only exception are integers, which are stored in the pointer if small enough.
Yes, you can do this quite easily already using the C FFI. |
It explains in the README that a goal for Koka is to support array programming better in the future, and I wanted to ask what that might look like, and what is currently possible.
f: 'a -> 'a
along a vector, and have this update in place. Is this: currently achievable, an eventual design goal, probably never going to happen, etc.A related question I have is that, by reading your group's papers, it seems that you can use effects to control stateful computation in the same way that Haskell does with the state monad and runST.
The vectors defined in the standard library are immutable. It is not clear to me whether Koka gives the programmer a way to use scoped effects to do stateful array computations, is there anything there? The documentation for the modify function talks about in-place updates for vectors but I unfortunately did not really understand that bit.
The text was updated successfully, but these errors were encountered: