3 ms·
They're very related. Due to Haskell's non-strict semantics, if a dynamic library, written in Haskell, that some Haskell program is linked to is recompiled, th
by Blikkentrekker 6y ago
They're very related.
Due to Haskell's non-strict semantics, if a dynamic library, written in Haskell, that some Haskell program is linked to is recompiled, then the code that is linked to it must also be recompiled.
- pklausler 6y agoWhy is this a necessary consequence of lazy execution?
- tome 6y agoI'm having trouble grasping that. Why would non-strict semantics imply that code must be recompiled if a dynamic library changes?
- Blikkentrekker 6y agoWith non-strict semantics, function execution is re-ordered and turned inside out. For instance let us say we have pseudocode: let list = [1,2,3,4,5]; let new_list = do_something(list); lew newer_list = do_something_else(new_list); Both these functions consume and return lists. In a strict language, this process of iterating over the entire list internally in these two functions would happen twice; this would be wasteful. A non-strict language however is permitted to take the side-effect-less code apart, and restructure it in such a way that the list is only traversed once, essentially combining these two functions into one function and letting what each does run successively, for this purpose it is permitted to generate a new function that combines what both does, and doing so iterating the list only once, and optimizers are typically clever enough to be able to do so. Suppose that both of these functions be library function black boxes, provided by a dynamic library, then the implementation can no longer do this as it calls both from a library. The way Haskell is written is completely dependent on this; it would be awfully slow if the compiler weren't allowed to do this. The result in practice is that updating a dynamic library written in Haskell requires that all it's consumers be recompiled to compile against the new version. Or otherwise said: there is no concept of a stable a.b.i. in Haskell.
- lalaithion 6y agoIn practice, Haskell doesn't do this. import System.IO.Unsafe import Prelude hiding (last) last :: [Int] -> Int last (x:[]) = x last (x:xs) = unsafePerformIO (do print x return (last xs)) secondToLast :: [Int] -> Int secondToLast (x:y:[]) = x secondToLast (x:xs) = unsafePerformIO (do print x return (secondToLast xs)) main = let list = [1,2,3,4,5,6] x = last list y = secondToLast list in print (x + y) The above code outputs 1 2 3 4 5 1 2 3 4 11 indicating that it traversed the list twice, fully completing one traversal before starting the next.
- Blikkentrekker 6y agoYes, it doesn't do it there on optimization level 2, however it does do it here for instance: import System.IO.Unsafe debug x = unsafePerformIO $ print x >> pure x map1 = map $ debug . (+ 1) map2 = map $ debug . (* 2) main = let list = [1,2,3,4,5,6] newlist = map1 list newerlist = map2 newlist in print newerlist The output of this is: 2 4 3 6 4 8 5 10 6 12 7 14 [4,6,8,10,12,14] Showing that it was smart enough to traverse once. If `map1` and `map2` were imported by some library, it would be close to impossible to speak of maintaining stable a.b.i.'s to both these functions without the compiler somehow being able to turn them inside out and traverse only once.