User loginNavigation |
archivesThose pesky higher-rank types. Or how to type \f x y. (f x, f y)As people might have noticed I've been somewhat interested in how to type g = \f x y. (f x, f y) Now you might think HM, as implemented in various languages, does a nice job typing that. Ocaml gives the most readable result as # let g f x y = (f x, f y);; val g : ('a -> 'b) -> 'a -> 'a -> 'b * 'b = Or you could go higher rank and type it g :: (forall a b. a -> b) -> a -> b -> (c, d) g = \f x y -> (f x, f y) But, for various reasons, I want to type it def g: (a -> f a) -> b -> c -> (f b, f c) = [f, x, y -> (f x, f y)] Since I am lazy and assume everything has been done in literature somewhere, does anyone have a reference with a typing system like that? PS. 'Solved' in Haskell. Courtesy of Sjoerd Visscher, Haskell allows for quantification over type constructors; though I want to avoid explicit quantifcation. g :: (forall a. a -> f a) -> b -> c -> (f b, f c) g f x y = (f x, f y) PPS. Gashe noticed that Haskell is unable to recognize that f should sometimes be unificated with 'id = /\a. a' *Main> g (+ 2) 3 4 :27:4: Couldn't match type `a' with `f0 a' `a' is a rigid type variable bound by a type expected by the context: a -> f0 a at :27:1 Expected type: a -> f0 a Actual type: a -> a In the first argument of `g', namely `(+ 2)' In the expression: g (+ 2) 3 4 In an equation for `it': it = g (+ 2) 3 4 Safe interior references in the presence of mutationSuppose like Rust & C/C++, we want to support references that point to the inside of another value. A reference<t> is something that can be dereferenced (deref : reference<t> -> t). A reference may also be mutable, so that we can set its value. It may also support other operations, such as walking a data structure. Examples:
Note that "reference" in the sense I'm using is not necessarily just a pointer. A tree iterator may maintain a stack of parent nodes in order to be able to traverse a singly linked tree. There's one nasty problem with references, which is that in the presence of mutation they can lead to memory unsafety or run time errors. Examples:
As you can see, it's not just a problem with pointers. Even in a language like Java, you have problems with iterators when the underlying data structure is mutated. At run time they may throw ConcurrentModificationException. Rusts type system attempts to prevent these kind of errors statically, but Rusts type system isn't fully finalized yet and it is quite complicated. I was wondering if there is existing literature on this problem and perhaps there is some elegant way to prevent this with types. It would probably involve linear types and capabilities. If such a thing does not exist yet, one thing I can think of is to require a linear capability in order to mutate the value, and in order to obtain a reference to the inside of the value you must give up this capability. In return you get a capability that allows you to read the references. If you later want to mutate again, you have to give up the capability to read the references. Is this a good approach? Why/why not? |
Browse archivesActive forum topics |
Recent comments
22 weeks 3 days ago
22 weeks 3 days ago
22 weeks 3 days ago
44 weeks 4 days ago
48 weeks 6 days ago
50 weeks 3 days ago
50 weeks 3 days ago
1 year 1 week ago
1 year 5 weeks ago
1 year 5 weeks ago