GHCã®ä¸éè¨èªCoreã¸ã®è±ç³ãè¦ãè¦ã
Haskell (ãã®3) Advent Calendar 2017 11æ¥ç®ã®è¨äºã(äºç´æ稿ç¥ããªãã£ãã®ã§ãã©ã¤ã³ã°ã«ãªã£ã)
GHCãã³ã³ãã¤ã«ã®éä¸ã§ä¸é表ç¾ã¨ãã¦ç¨ããCoreã®çæã£ã·ãã観å¯ããã
観å¯ãã¦ããã¼ã¯ãã¯ããªãã»ã©ã(ããã£ã¦ãªã)ãã¨è¨ãã ãã«ãªãããã
ã¯ããã«
GHCã¯Haskellã®ã½ã¼ã¹ã³ã¼ããä½ã¬ãã«ãªã³ã¼ãã¸ã¨ã³ã³ãã¤ã«ããéç¨ã§æ§ã ãªpass(ã³ã³ãã¤ã«ã®ã¹ãã¼ã¸)ãéãã¦ããã°ã©ã ãã¼ã¿ãå¤æããã 俯ç°å³ã¯ä¸è¨ã®ãªã³ã¯ã«è©³ããã
åãGHCã®è©±ãã©ããã§èãããã£ã¦ãã£ããããªãã¨æã£ãã®ã¯ã GHCãã³ã³ãã¤ã©ã®ä¸éè¨èªã¨ãã¦å®ç¾©ãã¦ããCoreãç¥ã£ãæã
ãã®Coreã¨åä»ããããä¸éè¨èªã¯Desugar passã«ã¦çæãããä¸è¨ã®ãããªæ§è³ªãæã£ã¦ããã
- å°ããªæ§æ
- 3ã¤ã®ãã¼ã¿åã¨15ã®å¤ã³ã³ã¹ãã©ã¯ã¿
- æç¸å¤æ°ã«ã¯å
¨ã¦åãã¤ãã¦ãã
- å段ã§æ¨è«ããã¦ãã
- å
¨ã¦åãã¤ãã¦ããããé«éã«åæ¤æ»ãã§ãã
- ããæ¨è«ã¯çµãã£ã¦ããã®ã§æ¤æ»ãé«é
- åç´ã ã大ããªè¡¨ç¾åãæã¤
- Haskellã®ã½ã¼ã¹ããã°ã©ã ãããã«å¤æããã
GHCã¯ãªãªã¼ã¹ã®ãã³ã«æ§ã ãªè¨èªæ¡å¼µãå¢ãã¦ãã¦ã 表é¢ä¸ã®æ§æã¯å¤æ§ã«ãªã£ã¦ãã¦ããã ããã«ãé¢ããããã®Coreã¨ããä¸éè¨èªã¯ä¸è¨ã®ãããªå°ãããä¿ã£ã¦ããã
- 3ã¤ã®ãã¼ã¿å
- 15ã®å¤ã³ã³ã¹ãã©ã¯ã¿
data Expr b = Var Id | Lit Literal | App (Expr b) (Arg b) | Lam b (Expr b) | Let (Bind b) (Expr b) | Case (Expr b) b Type [Alt b] | Cast (Expr b) Coercion | Tick (Tickish Id) (Expr b) | Type Type | Coercion Coercion deriving Data data AltCon = DataAlt DataCon | LitAlt Literal | DEFAULT deriving (Eq, Data) data Bind b = NonRec b (Expr b) | Rec [(b, (Expr b))] deriving Data type Arg b = Expr b type Alt b = (AltCon, [b], Expr b)
åå¤ã³ã³ã¹ãã©ã¯ã¿ãä¾åãã¦ããæ´ã«ç´°ãããã¼ã¿åã¯ããã«ããã Haskellã®ã½ã¼ã¹ã³ã¼ãã¯ä¸è¨ã®ãã¼ã¿åã«desugar(è±ç³)ããã¦åç´åãããã
æ£ç´ãåããã¹ã¦ã®ã³ã³ã¹ãã©ã¯ã¿ã®æå³ã解ã£ã¦ããããã§ã¯ãªãã ããããã®å¤å½©ãªè¡¨ç¾åãæã£ãHaskellã®æ§æã ãã®å°ããªCoreã«å¤æå¯è½ã§ãã ãã¨ã«å¤§ããé©ããã
ããã§ã¯ãããã®ãã¼ã¿åã®è©³ç´°ã«ã¯ç«ã¡å ¥ããã å®éã«Haskellã®ããã°ã©ã æ¸ããªãããã®desugarãããCoreãã©ãå¤åãã¦ããããè¦ã¦ã¿ããã¨æãã
観å¯ãã¦ã¿ã
ãã®ç¯ã§ã¯GHCã®ãããã°ãªãã·ã§ã³ã使ã£ã¦ã parseãããããã°ã©ã ãDesugar passãçµãå¾ã®çµæã確èªãã¦ã¿ãã
ã©ããªæãã§è¦ãããã ãã
Setup
stack.yamlã«ãªãã·ã§ã³ãã¤ãã¦ãããã
ghc-options: "*": -ddump-to-file -ddump-ds -ddump-simpl -dsuppress-idinfo -dsuppress-coercions -dsuppress-uniques -dsuppress-module-prefixes
é·ããé·ãããã©ãã¤ã³ã㯠-ddump-ds
ã®ã¿ã
-dsuppres
ç³»ã¯åé·ãªåºåãæ¸ããããã«æå®ãã¦ããã ãã
ãã®ãªãã·ã§ã³ãã¤ãã¦ããã¨stackã®ãã«ãã®ææç©ãæ ¼ç´ãã .stack-work
ãã£ã¬ã¯ããªã®ä¸ã«ã¬ãã¼ããåºåãããã
ä»å src/Lib.hs
ã«å®ç¾©ãæ¸ãä¸ãã¦ããããåºåçµæã¯
.stack-work/dist/x86_64-linux-nix/Cabal-1.24.2.0/build/src/Lib.dump-ds
ã¨ãããã¡ã¤ã«ã«åºåãããã
å®æ°
stringConst :: String stringConst = "Hello"
-- RHS size: {terms: 2, types: 0, coercions: 0} stringConst :: String stringConst = unpackCString# "Hello"#
ã¾ãããªããããããããã ããã
é¢æ°é©ç¨
falsy :: Bool falsy = not True
-- RHS size: {terms: 2, types: 0, coercions: 0} falsy :: Bool falsy = not True
å¤åãªããåç´éãããã
Infix
two :: Int two = 1 + 1
-- RHS size: {terms: 6, types: 1, coercions: 0} two :: Int two = + $fNumInt (I# 1#) (I# 1#)
ãªã«ãèµ·ããããã
äºé
æ¼ç®åãçµå±ã¯é¢æ°ãªã®ã§ã
+ 1 1
ã®ãããªSå¼ã£ã½ãè¦ãç®ã«ãªãã®ã¯ãããã
$fNumInt
ã¨ããè¬ã®ã·ã³ãã«ãåºã¦ããã
å¾ã§ãåºã¦ãããåã¯ã©ã¹ Num
ã® Int
ã¤ã³ã¹ã¿ã³ã¹å®ç¾©ã渡ãã¦ãã模æ§ã
é¢æ°åæ
notNot :: Bool -> Bool notNot = not . not
-- RHS size: {terms: 3, types: 3, coercions: 0} notNot :: Bool -> Bool notNot = . @ Bool @ Bool @ Bool not not
x . y
ã . x y
ã«å¤æãããã
ãããã¾ãäºé
æ¼ç®åã2å¼æ°ã®é¢æ°ã«å¤æããã¦ããã
ã ãã§ã¯ãªã㦠@ Bool
ãªãè¨å·ãåºã¦ããã
ãã㯠.
ãæã¤å¤ç¸æ§ã«é¢é£ããã
次ã§èª¬æã
å¤ç¸é¢æ°
identity :: a -> a identity x = x
-- RHS size: {terms: 3, types: 3, coercions: 0} identity :: forall a. a -> a identity = \ (@ a) (x :: a) -> x
ã¡ãã£ã¨å½¢ãå¤ãã£ãã大äºãªã¨ããã«ããã
Haskellã§å¿åé¢æ°ã¨ä½ãæã¯
\ x -> x
ã¨ããã
ãªã®ã§
\ (x :: a) -> x
ã¨ãªããªã解ãã ãaã¨ããåãæã¤xã¨ããå¤ãåãã¨ãããã®xãè¿ããã¨ãããããªæå³ã§èªããã
ãããå®éã¯
\ (@ a) (x :: a) -> x
ããã
(@ a)
å¿åé¢æ°ã«å¼æ°ãå¢ãã¦ããã
ãã㯠åå¤æ°ãé¢æ°ã®ä»®å¼æ°ã¨ãã¦å®ç¾©ããã¦ãã ãã¨ã表ãã
ã¨ã¦ãä¸æè°ã
-- å å¤ \ (@ a) (x :: a) -> x
åã¨å¤ãååã®å¼æ°ã¨ãã¦æ±ããã¦ãããã¨ã«ãªãã
Coreã§ã¯åã®å¼æ°ã¨å¤ã®å¼æ°ãååã«æ±ããã¦é¢æ°ã«é©ç¨ãããã
ãªã®ã§ãã®é¢æ°ã«å¼æ°ãé©ç¨ããå ´åã¯ã
identity Int 1
ã®ããã«ãã¦åå¼æ°ã決å®ãããå¤å¼æ°ã決å®ããã¦ãããã®ã¨æãããã
è£è¶³: forall ã«ã¤ãã¦
identity :: forall a. a -> a
forall
ã表ãããæå³çã«ã¯ãã¨ã® a -> a
ã¨ãªããå¤ãããªãã
ç³è¡£æ§æã¨ã㦠forall
ã®çç¥ã許容ããã¦ãããã®ãã
è±ç³ãçµã¦æ示åãããã ãã
è£è¶³: Coreä¸ã®è¡¨ç¾
ãã®é¢æ°ãCoreä¸ã§ã©ã表ç¾ããã¦ãããã¨ããã¨
Lam (TyVar "a") (Lam (Id "x") (Var (Id "x")))
ã©ã ãè¨ç®ã£ã½ãæ¸ãã¨
λ a. λ x: a. x
ãããªæã?
(解ããªããã© a ã«ã¯kindã¨ã㦠*
ã§ãã¤ãã®ããªï¼)
1ã¤ãã®ã©ã ãæ½è±¡ã®å¼æ°ã¯åã§ã 2ã¤ãã®ã©ã ãæ½è±¡ã®å¼æ°ã¯aåã®å¤xã¨ãªãã
ãã®2ã¤ã®å¼æ°ã¯Coreè¨èªå
㧠Var
ã¨ããåãæã¤ã
åã¨å¤ãååã§å¼æ°ã«ãªãä»çµã¿ã¯ç°¡åã§ã
é¢æ°ã®å¼æ°ã«æç¸ããããã¼ã¿å Var
ãä¸è¨ã®ããã«ãªã£ã¦ããããã
data Var = TyVar ... -- åã¬ãã«ã®å¤æ° | TcTyVar ... -- ä¸æ "Used for kind variables during inference" ããã | Id ... -- å¤ã¬ãã«ã®å¤æ°
ãã®é¢æ°ã®å¼æ°ã«ä¸ãããããã¼ã¿ã
TyVar
: åId
: å¤
ã©ã¡ããåãä»ããããã«ãªã£ã¦ããã
å¤ç¸é¢æ°ã®é©ç¨ (åå¤æ°ã決å®ãããã®ãï¼)
æ¬å½ã«åãå¼æ°ã¨ãã¦é¢æ°ã«é©ç¨ããã¦ããã®ãã観å¯ã å ç¨ã®å¤ç¸é¢æ°ã«å¼æ°ãé©ç¨ãã¦ã¿ãã
one :: Int one = identity 1
-- RHS size: {terms: 3, types: 1, coercions: 0} one :: Int one = identity @ Int (I# 1#)
äºæ³éãã
@ Int
ã§ç¢ºãã«åãé©ç¨ãã¦ããã
é«éé¢æ°
ããªãã¿ã®é¢æ°åæã
comp :: (b -> c) -> (a -> b) -> a -> c comp f g x = f (g x)
-- RHS size: {terms: 9, types: 11, coercions: 0} comp :: forall b c a. (b -> c) -> (a -> b) -> a -> c comp = \ (@ b) (@ c) (@ a) (f :: b -> c) (g :: a -> b) (x :: a) -> f (g x)
å¼æ°ããåããããã
ã ããã©ãåå¤æ°ã®æ½åºã«ã¼ã«ã¯ãã¯ãæ確ã ã
åå¤æ°ã¯ b
c
a
ã®é ã§ç»å ´ããã
ããã«åãã㦠forall b c a
ã®é ã§å®ç¾©ãããã
ããã« forall
ã«ç¶ãåå¤æ°ã¯Coreã®ã©ã ãæ½è±¡ã§å¼æ°ã«ãªãã
ãã¿ã¼ã³ããã
hasValue :: Maybe a -> Bool hasValue (Just _) = True hasValue Nothing = False
-- RHS size: {terms: 8, types: 7, coercions: 0} hasValue :: forall a. Maybe a -> Bool hasValue = \ (@ a) (ds :: Maybe a) -> case ds of _ { Nothing -> False; Just _ -> True }
é¢æ°å®ç¾©é¨ã«ããããã¿ã¼ã³ãããã¯case ofæ§æã«å¤æããã¦ããã
Coreã®Caseã³ã³ã¹ãã©ã¯ã¿ã«å¤æããã¦ãããããã
Case (Expr b) b Type [Alt b]
å®ã¯ãã®ã³ã³ã¹ãã©ã¯ã¿ b
㨠Type
ã®é¨åãã¾ã ä½è
ãå¤æãã¦ããªãã
b
ã Expr b
ãæç¸ãã¦ããã Type
ã [Alt b]
ã®å¼ã®åã注éãã¦ããï¼
åã¯ã©ã¹å¶ç´
åã¯ã©ã¹ã¤ãã®é¢æ°ãå®ç¾©ããã¨ã©ããªãã ãããã
join :: (Monad m) => m (m a) -> m a join = (>>= id)
-- RHS size: {terms: 8, types: 17, coercions: 0} join :: forall (m :: * -> *) a. Monad m => m (m a) -> m a join = \ (@ (m :: * -> *)) (@ a) ($dMonad :: Monad m) (ds :: m (m a)) -> >>= @ m $dMonad @ (m a) @ a ds (id @ (m a))
æ¬æ°ãªå¤æ°ãåºã¦ããã å¼æ°é¨åãå解ãã¦ä¸ã¤ä¸ã¤èªã¿è§£ããã
(@ (m :: * -> *)) -- Monadã®ã¤ã³ã¹ã¿ã³ã¹ã¨ãªãã¹ãå (@ a) -- mã§ä¿®é£¾ãããå ¥åå¤ã®åã®ä¸é¨ ($dMonad :: Monad m) -- åã¯ã©ã¹ãæºããã¤ã³ã¹ã¿ã³ã¹ã®å®ç¾© (ds :: m (m a)) -- å®éã®é¢æ°ã®å ¥åå¤
join
ã«è¡¨ããåå¤æ°ã¯ m
㨠a
ã
ãªã®ã§ãã®2ã¤ã¯æåã« (@ (m :: * -> *))
㨠@ a
ã¨ãã¦æç¸ãããã
(ds :: m (m a))
ã¯å®éã®é¢æ°ã®å¼æ°ãªã®ã§çåãªãã
åé¡ã¯ ($dMonad :: Monad m)
ã¨ããã©ãããåºã¦ããã®ã解ããªãæç¸ã
ããã¯åã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãé¢æ°ã®å¼æ°ã¨ãã¦åãåãããã®æç¸ãããã
ã¨ãããã¨ã¯ãåã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã渡ãã¦ããã¨ãããè¦ããããããããªãããã
åã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹é©ç¨
ããã»ã©å®ç¾©ãã join
ã使ã£ã¦ã¿ããã
maybeOne :: Maybe Int maybeOne = join (Just (Just 1))
-- RHS size: {terms: 6, types: 5, coercions: 0} maybeOne :: Maybe Int maybeOne = join -- (@ (m :: * -> *)) @ Maybe -- (@ a) @ Int -- ($dMonad :: Monad m) $fMonadMaybe -- (ds :: m (m a)) (Just @ (Maybe Int) (Just @ Int (I# 1#)))
ã³ã¡ã³ãã§å
ç¨ã® join
ã®å®ç¾©ã¨å¯¾ç
§ãã¦ã¿ãã
Monad
ã®ã¤ã³ã¹ã¿ã³ã¹å®ç¾©ãåãåãé¨åã«ã¯
$fMonadMaybe
ãã
ååããå¯ããã«ã©ãããMaybeã®ã¤ã³ã¹ã¿ã³ã¹å®ç¾©ã渡ããã¦ããããã ã (Scalaãåã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã¨ãã¦implicitãã©ã¡ã¼ã¿ã§æ¸¡ãã¦ãããã®ã¨ãã»ã¼åããã®ã ã¨æãããã)
Monad
æå¾ã«ã¢ãããå«ãdoè¨æ³ãã©ã®ããã«Coreã«å¤æãããã®ããè¦ã¦ã¿ãã
printArgs :: IO () printArgs = do args <- System.Environment.getArgs print args
-- RHS size: {terms: 7, types: 8, coercions: 0} printArgs :: IO () printArgs = >>= @ IO $fMonadIO @ [String] @ () getArgs (\ (args :: [String]) -> print @ [String] $dShow args)
doã¯ç³è¡£æ§æãªã®ã§è±ç³å¾ã¯ >>=
ã使ã£ãå¼ã«å¤æãããã®ã¯äºæ³ã§ããã
åå¨ãã¯æã£ãããããããæ··ãã£ã¦ãã¦æ··ä¹±ã ä¸ããè¦ã¦ããã
bindé¢æ°ã®å®ç¾©ã(åå¶ç´ã¯é¤ã)
>>= :: m a -> (a -> m b) -> m b
ãã㯠forall
ã¤ãã§è¡¨ç¾ããã¨
>>= :: forall m a b. m a -> (a -> m b) -> m b
ã¨ãªãã
ãã£ã¦
(@ (m :: * -> *)) (@ a) (@ b)
ãåå¤æ°ã¨ãã¦é¢æ°ã®å¼æ°ã«æ½åºãããã å®éã®å¯¾å¿ãã¿ã¦ã¿ãã¨
-- (@ (m :: * -> *)) @ IO -- ããã¯Monadã®ã¤ã³ã¹ã¿ã³ã¹ã¨ãã¦IOã®å®ç¾©ã渡ãã¦ãã $fMonadIO -- (@ a) @ [String] -- (@ b) @ ()
ãããã使ã㨠>>=
ã¯ä¸è¨ã®ããã«å
·è±¡åãããã
-- getArgsãã printãã >>= :: IO [String] -> ([String] -> IO ()) -> IO ()
åå¤æ°ã ã£ãé¨åå ¨ã¦ã«å ·ä½çãªåãå½ã¦ã¯ã¾ã£ãã
ã¾ã¨ã
Haskellã®ããã°ã©ã ã¯desugar(è±ç³)å¾ã«Coreã¨ããä¸éè¨èªã«å¤æãããã
Coreã¯åºæ¬çã«åä»ãã©ã ãè¨ç®(ã®å¤ç¨®)ãªã®ã§
- å¤æ°
- é¢æ°ã®å®ç¾©
- é¢æ°ã®é©ç¨
- ãã®ä» Let, Case ...
ãªã©ã®ããããªå®ç¾©ã§æ§æãããã
ããã«å¤ã¨åãåã¬ãã«ã§æç¸ãããã©ã ãæ½è±¡ãç¨ãããã¨ã§
- åã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹æ¸¡ã
- å ·è±¡åã®æ±ºå®
ãªã©ã®æä½ã ãã ã®é¢æ°é©ç¨ ã§å®ç¾ããã¦ããã
å°ãªãè¦åã§å¤å½©ãªã¦ã¼ã¹ã±ã¼ã¹ãå®ç¾ãã¦ãã好ä¾ãGHCã®ä¸ã«æ½ãã§ãããã¨ãç¥ããã¨ãã§ãã¦ããã£ãã
Less is more.
Yoshiko is Yohane.
Reference
- Simon Peyton Jones Into The Core
- GHC Compiler pass
- Coreã®API Document in GHC 8.2.2
- GHCã®ãããã°ãªãã·ã§ã³
- GHCã«ãããå¤å½©ãªæ å ±ã®åºåæ¹æ³
- ãã£ã¨è¸ã¿è¾¼ãã 解æ Dive into GHC: Targeting Core
- ãã®è¨äºãããã¡ããã¨èª¿ã¹ã¦ãã: GHC Core by example, episode 1: Hello, Core!
ä¸è¨ãä½è«
ã¢ããã¼ã·ã§ã³
Haskell Day 2016ãæ¥æ¬ã§éå¬ãããæã«Simon Peyton Jonesããã"Into the Core"ã¨ããã¿ã¤ãã«ã§ãã¬ã¼ã³ããããããã æ®å¿µãªããåã¯é½åãã¤ããèãã«ãããªãã£ãããã©ãåããã¼ãã®è¬æ¼ãåç»ã«åãããã¦ããã®ã§ããããªã³ã¯ãã¦ããã
Into the Core - Squeezing Haskell into Nine Constructors by Simon Peyton Jones
æ©å£éãã¦99%ä½ãè¨ã£ã¦ããã®ãåã«ã¯è§£ããªãã ããã©ã¨ããã©ãããªãã¨ãªãä¼ããæ°ãããã
ãã¬ã¼ã³ã§ä½¿ã£ãã¹ã©ã¤ã㯠ãã¡ã
ãããã¼ãããèãã¦ãã¦ãCoreã£ã¦ãªãã ãé¢ç½ããªãã¨æã£ãã®ããã£ããã
ãããã
Coreã®çè«çèæ¯ã«ãªã£ã¦ããSystemFã¨ããã©ã ãè¨ç®ã®ä¸ç¨®ãä½è ãªã®ãæ°ã«ãªãã
GHCã§ç¨ãããã¦ããSystemFCã¨ããå¤ç¨®ã«ã¤ãã¦ã¯ä¸è¨ã®ãªã³ã¯ãåèã«ãªãããã ãã©ã
System F with type equality coercions
åã¯ããããã©ã ãè¨ç®ç´ 人ãªã®ã§ä¸è¨ã®æ¸ç±ãèªã¿é²ããå¿ è¦ãããããã
åã·ã¹ãã å ¥é ããã°ã©ãã³ã°è¨èªã¨åã®çè«
æçã§
- 3ç« : åç¡ãç®è¡å¼
- 8ç« : åä»ãç®è¡å¼
- 9ç« : åç´åä»ãã©ã ãè¨ç®
- 23ç« : å ¨ç§°å
ãèªãã°è¾¿ãçããããã«è¦ããã
ããã¼ã»ãã¨ããªãããã