Unit unboxed tuples

Dan Doel dan.doel at gmail.com
Wed Jan 11 20:28:37 CET 2012


On Wed, Jan 11, 2012 at 8:41 AM, Simon Marlow <marlowsd at gmail.com> wrote:
> On 10/01/2012 16:18, Dan Doel wrote:
>>
>> Copying the list, sorry. I have a lot of trouble replying correctly
>> with gmail's interface for some reason. :)
>>
>> On Tue, Jan 10, 2012 at 11:14 AM, Dan Doel<dan.doel at gmail.com>  wrote:
>>>
>>> On Tue, Jan 10, 2012 at 5:01 AM, Simon Marlow<marlowsd at gmail.com>  wrote:
>>>>
>>>> On 09/01/2012 04:46, wren ng thornton wrote:
>>>>>
>>>>> Shouldn't (# T #) be identical to T?
>>>>
>>>>
>>>> No, because (# T #) is unlifted, whereas T is lifted.  In operational
>>>> terms,
>>>> a function that returns (# T #) does not evaluate the T before returning
>>>> it,
>>>> but a function returning T does.  This is used in GHC for example to
>>>> fetch a
>>>> value from an array without evaluating it, for example:
>>>>
>>>>  indexArray :: Array# e ->  Int# ->  (# e #)
>>
>>
>> I don't really understand this explanation. (# T #) being unlifted
>> would mean it's isomorphic to T under the correspondence e<->  (# e
>> #). _|_ = (# _|_ #) : (# T #), so this works.
>>
>> Does the difference have to do with unboxed types? For instance:
>>
>>    foo :: () ->  Int#
>>    foo _ = foo ()
>>    bar :: () ->  (# Int# #)
>>    bar _ = (# foo () #)
>>
>>    baz = case bar () of _ ->  5  -- 5
>>    quux = case foo () of _ ->  5 -- non-termination
>>
>> Because in that case, either (# Int# #) is lifted, or the Int# is
>> effectively lifted when inside the unboxed tuple. The latter is a bit
>> of an oddity.
>
>
> Unboxed types cannot be lifted, so in fact bar compiles to this:
>
>  bar = \_ -> case foo () of x -> (# x #)
>
> and both baz and quux diverge.
>
> It might help to understand (# T #) by translating it to (# T, () #).
> There's really no difference.

Then I'm afraid I still don't understand the difference. Is it that
case in core always evaluates? So:

    case undefined of x -> ...

blows up, while

    case (# undefined #) of (# x #) -> ...

does not?

Also, if so, how is (core-wise):

    foo :: ... -> (# T #)
    case foo <v> of (# x #) -> ...

different from:

    foo :: ... -> T
    let x = foo <v> in ...

Stack vs. heap allocation?

Sorry for being rather thick.

-- Dan



More information about the Glasgow-haskell-users mailing list