
The well-known ST monad uses an ingenious hack to make it impossible for distinct ST computations to interact with each other. Is there a way to do something similar so that I can create "cursors" that reference a (mutable) container, and then write a function that takes two cursor arguments which are statically guaranteed to refer to the same container?

On 16 March 2011 11:31, Andrew Coppin
The well-known ST monad uses an ingenious hack to make it impossible for distinct ST computations to interact with each other.
Is there a way to do something similar so that I can create "cursors" that reference a (mutable) container, and then write a function that takes two cursor arguments which are statically guaranteed to refer to the same container?
You could define a function: withContainer ∷ (∀ s. Container s → α) → α which creates a container, parameterizes it with an 's' that is only scoped over the continuation and applies the continuation to the created container. If you then define a function to create a cursor from it like: cursor ∷ Container s → Cursor s it is statically guaranteed that two Cursors parameterized with the same 's' refer to the same container: foo ∷ Cursor s → Cursor s → ... because the only way to create a Container s is through withContainer. Regards, Bas

You could define a function:
withContainer ∷ (∀ s. Container s → α) → α
which creates a container, parameterizes it with an 's' that is only scoped over the continuation and applies the continuation to the created container.
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...

I fail to see how does it limit the scope. 16.03.2011 15:05, Andrew Coppin пишет:
You could define a function:
withContainer ∷ (∀ s. Container s → α) → α
which creates a container, parameterizes it with an 's' that is only scoped over the continuation and applies the continuation to the created container.
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi Andrew, Andrew Coppin wrote:
You could define a function:
withContainer ∷ (∀ s. Container s → α) → α
which creates a container, parameterizes it with an 's' that is only scoped over the continuation and applies the continuation to the created container.
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
You can write helper functions which take containers as argument by parameterizing these helper functions over s: takesTwoContainers :: Container s1 -> Container s2 -> ... takesTwoContainers c1 c2 = ... -- c1 and c2 can be used here This function could be called like this: withContainer (\c1 -> withContainer (\c2 -> takesTwoContainers c1 c2)) -- c1 and c2 can be used here In this example, the scope of the containers is not limited to a single span of code. Tillmann

Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
You can write helper functions which take containers as argument by parameterizing these helper functions over s:
takesTwoContainers :: Container s1 -> Container s2 -> ... takesTwoContainers c1 c2 = ... -- c1 and c2 can be used here
This function could be called like this:
withContainer (\c1 -> withContainer (\c2 -> takesTwoContainers c1 c2)) -- c1 and c2 can be used here
In this example, the scope of the containers is not limited to a single span of code.
What you can't do is write functions such as foo :: Container x -> (Cursor x, Cursor x) for example. Perhaps this property is just too tricky to check in the type system. It's quite possible to check it at run-time; I'd just prefer to check at compile-time, if it's not too difficult to implement. I thought of a further complication: What happens if you concatinate two containers? Then cursors to each of the original containers all become valid for the new, concatenated container. I suppose you could issue a new phantom type variable for the concatenated version, but the whole idea of mutable containers is to, you know, mutate them. Given the above, perhaps it's just not possible to check this kind of thing statically at all.

On Wed, Mar 16, 2011 at 7:52 AM, Andrew Coppin
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
You can write helper functions which take containers as argument by parameterizing these helper functions over s:
takesTwoContainers :: Container s1 -> Container s2 -> ... takesTwoContainers c1 c2 = ... -- c1 and c2 can be used here
This function could be called like this:
withContainer (\c1 -> withContainer (\c2 -> takesTwoContainers c1 c2)) -- c1 and c2 can be used here
In this example, the scope of the containers is not limited to a single span of code.
What you can't do is write functions such as
foo :: Container x -> (Cursor x, Cursor x)
for example.
I don't follow. foo = cursor &&& cursor Did you mean to have some extra condition on foo that can't be satisfied? Luke

On 3/16/11 9:52 AM, Andrew Coppin wrote:
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
You can write helper functions which take containers as argument by parameterizing these helper functions over s:
takesTwoContainers :: Container s1 -> Container s2 -> ... takesTwoContainers c1 c2 = ... -- c1 and c2 can be used here
This function could be called like this:
withContainer (\c1 -> withContainer (\c2 -> takesTwoContainers c1 c2)) -- c1 and c2 can be used here
In this example, the scope of the containers is not limited to a single span of code.
What you can't do is write functions such as
foo :: Container x -> (Cursor x, Cursor x)
for example.
-- ? foo cx = (curse cx, curse cx)
Perhaps this property is just too tricky to check in the type system. It's quite possible to check it at run-time; I'd just prefer to check at compile-time, if it's not too difficult to implement.
It sounds like you want something based on "memory regions". The ST monad uses a restricted version of regions, but there are more general versions which allow for comparing region names for equality etc (as opposed to ST where the existential quantification requires the types to unify or be unequal). Try googling around. -- Live well, ~wren

On Wed, Mar 16, 2011 at 12:05:56PM +0000, Andrew Coppin wrote:
withContainer ∷ (∀ s. Container s → α) → α
Hmm, yes. That will work, but I wonder if there's some way of doing this that doesn't limit the scope of the container to one single span of code...
You can just pack the container into an existential and pass that around freely. Only the use of cursors is limited into a scope where the owning container's type variable is visible (which you get by unpacking the existential). Lauri
participants (7)
-
Andrew Coppin
-
Bas van Dijk
-
Lauri Alanko
-
Luke Palmer
-
Miguel Mitrofanov
-
Tillmann Rendel
-
wren ng thornton