开发者

What is the point of the strictness declaration?

开发者 https://www.devze.com 2023-03-11 10:00 出处:网络
I am starting Haskell and was looking at some libraries where data types are defined with \"!\". Example from the bytestring library:

I am starting Haskell and was looking at some libraries where data types are defined with "!". Example from the bytestring library:

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- offset
                     {-# UNPACK #-} !Int                -- length

Now I saw this question as an explanation of what this means and I guess it is fairly easy to understand. But my question is now: what is the point of using this? Since the expression will be evaluated whenever it is need, why would you force the early evaluation?

In the second answer to this question C.V. Hansen says: "[...] sometimes the overhead of la开发者_StackOverflowzyness can be too much or wasteful". Is that supposed to mean that it is used to save memory (saving the value is cheaper than saving the expression)?

An explanation and an example would be great!

Thanks!

[EDIT] I think I should have chosen an example without {-# UNPACK #-}. So let me make one myself. Would this ever make sense? Is yes, why and in what situation?

data MyType = Const1 !Int
            | Const2 !Double
            | Const3 !SomeOtherDataTypeMaybeMoreComplex


The goal here is not strictness so much as packing these elements into the data structure. Without strictness, any of those three constructor arguments could point either to a heap-allocated value structure or a heap-allocated delayed evaluation thunk. With strictness, it could only point to a heap-allocated value structure. With strictness and packed structures, it's possible to make those values inline.

Since each of those three values is a pointer-sized entity and is accessed strictly anyway, forcing a strict and packed structure saves pointer indirections when using this structure.

In the more general case, a strictness annotation can help reduce space leaks. Consider a case like this:

data Foo = Foo Int

makeFoo :: ReallyBigDataStructure -> Foo
makeFoo x = Foo (computeSomething x)

Without the strictness annotation, if you just call makeFoo, it will build a Foo pointing to a thunk pointing to the ReallyBigDataStructure, keeping it around in memory until something forces the thunk to evaluate. If we instead have

data Foo = Foo !Int

This forces the computeSomething evaluation to proceed immediately (well, as soon as something forces makeFoo itself), which avoids leaving a reference to the ReallyBigDataStructure.

Note that this is a different use case than the bytestring code; the bytestring code forces its parameters quite frequently so it's unlikely to lead to a space leak. It's probably best to interpret the bytestring code as a pure optimization to avoid pointer dereferences.

0

精彩评论

暂无评论...
验证码 换一张
取 消