2016-07-07 77 views
3

我爲Core Haskell編寫了一個自定義的漂亮打印機,以便更好地研究Core的結構。這臺漂亮的打印機的要點是它需要一個CoreModule,並在輸出中包含數據構造函數,默認情況下Outputable實現看起來沒有。Core Haskell將函數應用於函數是什麼意思?

這裏是我上運行的漂亮打印機模塊的代碼:

module Bar2 where 

add :: Int -> Int -> Int 
add a b = a + b 

add2 a b = a + b 

這裏是漂亮的打印輸出:

------------------------------- Module Metadata -------------------------------- 
Module { "main" :: modulePackageId, "Bar2" :: moduleName } 
-------------------------------- Type Bindings --------------------------------- 
[r0 :-> Identifier ‘add’, rjH :-> Identifier ‘add2’] 
-------------------------------- Core Bindings --------------------------------- 
NonRec (Id "add2") 
     (Lam (TyVar "a") 
      (Lam (Id "$dNum") 
       (Lam (Id "a1") 
         (Lam (Id "b") 
          (App (App (App (App (Var (Id "+")) 
               (Type (TyVar (TyVar "a")))) 
              (Var (Id "$dNum"))) 
            (Var (Id "a1"))) 
           (Var (Id "b"))))))) 

NonRec (Id "add") 
     (Lam (Id "a") 
      (Lam (Id "b") 
       (App (App (App (App (Var (Id "+")) 
            (Type (TyConApp (Int) []))) 
           (Var (Id "$fNumInt"))) 
          (Var (Id "a"))) 
         (Var (Id "b"))))) 
--------------------------------- Safe Haskell --------------------------------- 
Safe 
------------------------------------- End -------------------------------------- 

什麼是困惑我的是,在這兩個實例中,Core似乎在接受參數前將+函數以及一些$dNum$fNumInt應用類型變量或類型構造函數。

對於add函數,類型也是明確給出的,而add2由編譯器推理決定。這似乎也影響了lambda函數鏈需要評估的參數數量,其中add需要2個,而add2需要4個。

這是什麼意思?

回答

7

核心幾乎是SystemF(技術上SystemFC)。在SystemF中,類型變量也需要是該函數的參數。在你的榜樣,哈斯克爾推斷

add2 :: Num a => a -> a -> a 
add2 a b = a + b 

這解釋了TyVar "a"參數add2

此外,Haskell必須找到一種方法,根據參數ab的類型是什麼類型,調度到「右」功能集合Num功能。它通過爲每個類型類約束創建一個字典參數。這是Id $dNum的說法。在add的情況下,Haskell已經知道哪個字典可以找到合適的(+)函數,因爲它知道它知道該操作在Int(所以不需要傳入:它只是$fNumInt)。

本質上,發生在引擎蓋下的是,對於每個類型類Haskell創建了一個帶有typeclass內部函數的字段的記錄data $d<Class> = ...。然後,對於每個實例,它會產生另一個$f<Class><Type> :: $d<Class>This is explained in more detail here

Here is another excellent answer describing Core related things.

5

在GHC 8.x中可以用在Haskell類型的參數發揮好,與核心。以下是一些基於發佈代碼的更多註釋示例。

add :: Int -> Int -> Int 
add a b = (+) @ Int a b 

(+) @ Int專業多態性(+)運營商,使其工作在Int類型。

在Core中,您還會看到在類別$fNumInt附近傳遞的類字典字典。

add2 :: forall n. Num n => n -> n -> n  
add2 a b = (+) @ n a b 

這基本上是一樣的,只是n是未知的。

在覈心,add2需要隱藏的「類型值」參數n(混淆性稱爲a在貼例子,即(Lam (TyVar "a") ...),然後將其轉發到(+)作爲類型參數。由於字典現在是未知的,所以在Core中有另一個隱藏的參數:字典必須由調用者add2傳遞,然後將其轉發到(+)。這個額外的參數被稱爲$dNum(見(Lam (Id "$dNum") ...)。

相關問題