Czy GHC kiedykolwiek rozpakowuje typy sum, przekazując je do funkcji? Na przykład, powiedzmy, że mamy następujące rodzaje:Konwencja wywoływania GHC dla argumentów funkcji typu suma
data Foo
= Foo1 {-# UNPACK #-} !Int {-# UNPACK #-} !Word
| Foo2 {-# UNPACK #-} !Int
| Foo3 {-# UNPACK #-} !Word
Potem zdefiniować funkcję, która jest straszny w swojej Foo
argumentu:
consumeFoo :: Foo -> Int
consumeFoo x = case x of ...
w czasie wykonywania, gdy zgłoszę consumeFoo
, co mogę spodziewać się? GHC calling convention ma przekazywać argumenty w rejestrach (lub na stosie, gdy jest ich zbyt dużo). Widzę dwa sposoby na to, aby argument przemijał:
- Wskaźnik na
Foo
na stercie zostaje przekazany jako jeden argument. - Stosuje się trzyargumentową reprezentację
Foo
, jeden argument reprezentujący użyty konstruktor danych i dwa pozostałe reprezentujące możliwe wartościInt
iWord
w konstruktorze danych.
Wolałbym drugą reprezentację, ale nie wiem, czy tak naprawdę to się dzieje. Jestem świadomy lądowania w GHC 8.2, ale nie jest jasne, czy robi to, co chcę. Gdybym zamiast tego napisał funkcję jako:
consumeFooAlt :: (# (# Int#, Word# #) | Int# | Word# #) -> Int
Wtedy oczekiwałbym, że ocena (2) będzie tym, co się stanie. A Unpacking section strony sum niespakowanego wskazuje, że mogę to zrobić również:
data Wrap = Wrap {-# UNPACK #-} !Foo
consumeFooAlt2 :: Wrap -> Int
i że powinien również mieć reprezentację chcę, myślę.
Moje pytanie brzmi: bez użycia typu opakowania lub surowej rozpakowanej sumy, w jaki sposób mogę zagwarantować, że suma zostanie rozpakowana do rejestrów (lub na stos), gdy przekazuję ją jako argument do funkcji? Jeśli jest to możliwe, czy jest to coś, co GHC 8.0 może już zrobić, czy jest to coś, co będzie dostępne tylko w GHC 8.2?