brokenix,
- Meaning of the linear arrow: f :: s ⊸ t guarantees that if (f u) is consumed exactly once,then the argument u is consumed exactly once(Consume exactly once).to consume exactly once • (like Int or Ptr) - just evaluate it.• unction value -apply it to one argument, consume its resultexactly once.• pair - pattern-match on it, consume each component exactlyonce.• adt, pattern-match on it,, all its linear components a linear arrow specifies how f uses its argument. It does not restrict
arguments to which function can be applied.a linear f cannot assume that itis given unique pointer to its argument. For example, if f :: s ⊸ t, then this is fine:g :: s → tg x = f xThe type of g makes no particular guarantees about the way in which it uses x; in particular, g canpass that argument to f.result of (unsafeFreeze ma) is a new immutable array, but toavoid an unnecessary copy, it is actually ma. The intention is, of course, that that unsafeFreezeshould be the last use of the mutable array; but nothing stops us continuing to mutate it further,with quite undefined semantics. The “unsafe” in the function name is a ghc convention meaning“ programmer has a proof obligation here that the compiler cannot check”.other unsatisfactory thing about the monadic approach to array construction is that it isoverly sequential. Suppose you had a pair of mutable arrays, with some updates to perform to each;these updates could be done in parallel, but the ST monad would serialise them• Operations on files remain monadic, unlike the case with mutable arrays. I/O operations
affect world, hence must be sequenced. It is not enough to sequence operations on
files individually, as it was for arrays.
• generalise the IO monadst it expresses whether or not returned value is linear.
extra multiplicity type parameter p to the monad IOL, where p can be 1 or ω,
indicating a linear or unrestricted result, respectively. Now openFile returns IOL 1 File, the “1”
indicating that the returned File must be used linearly.
• As before, operations on linear values must consume their input and return a new one; here
readLine consumes the File and produces a new one.
• Unlike the File, the ByteString returned by readLine is unrestricted, and the type of readLine
indicates this.
- Uniqueness (or ownership) types ensure that an argument of a function is not used elsewhere in an expression’s context even if the callee can work with the argument as it pleases. Linear types and uniqueness types have a ‘weak duality:’ ‘Seen as a system of constraints, uniqueness typing is a non-aliasing analysis, while linear typing provides a cardinality analysis.’1
- API for pure mutable arrays, the original Linear #Haskell paper [2] (Arxiv version) featured the function:
newMArray :: Int -> (MArray a %1 -> Ur b) %1 -> Ur b
- Taking a linear function as an argument, newMArray can make sure that the MArray is, in fact, not aliased. This is because linear types only restrict how a function can use an argument, it can’t restrict how the context uses an argument or a returned value. Contrast with uniqueness types (aka ownership types) in languages like Rust or Clean, which can demand that a value not be aliased. So, whenever we use linear types, in Haskell, to implement an API with a uniqueness requirement, we end up with such a newX function that takes a linear-function argument With
newMArray
andnewMArrayBeside
we have two functions to create new arrays. This isn’t satisfactory, but it gets worse. If I have another type with uniqueness constraints, say a ring buffer, then I’ll eventually need the ability to allow a ring buffer to piggyback on an array’s scope, and an array to piggyback on a ring buffer’s scope. with n types that can only be used linearly, I’ll need n^ 2 new functions. This is simply not sustainable. 3- of the many problems with Monads, one of them is that they are not composable, and Monad transformers are just a hack, you still have a stack of monads and how they interact when control flow gets involved can be hard to predict. Compare this with uniqueness typing (and syntax sugars for in/out arguments) and it's trivial to have multiple states used by the same function 4
Add comment