2017-04-27 91 views
19

these對DSL的無標籤的最終解釋很酷的註釋部分2.3,奧列格Kiselyov展示瞭如何解決解析問題的一個序列化的DSL表達式一次,解釋它多次。拷貝機解釋與高階像差

簡單地說,他表示「假一流多態性」的同類型

newtype Wrapped = Wrapped (∀ repr. ExpSYM repr ⇒ repr) 
fromTree :: String → Either ErrMsg Wrapped 

並不令人滿意,因爲它是不可擴展的:我們必須對每設置的不同Wrapper/fromTree限制repr。因此,我傾向於使用他的解決方案複製解釋器。這個問題是關於如何在HOAS中使用該解釋器。

具體而言,考慮目標語言綁定以下語言:

class Lam repr where 
    lam :: (repr a -> repr b) -> repr (a -> b) 
    app :: repr (a -> b) -> repr a -> repr b 

我無法給Lam類的聲音例如我的複印機解釋。下面是我有:

data Dup repr1 repr2 a = Dup {unDupA :: repr1 a, unDupB :: repr2 a} 

instance (Lam repr1, Lam repr2) => Lam (Dup repr1 repr2) where 
    lam f = Dup (lam $ unDupA . f . flip Dup undefined) (lam $ unDupB . f . Dup undefined) 
    app (Dup fa fb) (Dup a b) = Dup (app fa a) (app fb b) 

是否有某種方式來給出一個Lambda遞歸例如的東西,像我Dup型,不涉及undefined

我也利用this paper,允許單子口譯與人道主義組織和機構的lam的更強大的版本,但我沒有看到它如何幫助我的實例Dup嘗試。使用HOAS版本lam的解決方案將會非常棒!


*:奧列格展示瞭如何使用定義德布魯因指數健全的情況下,但我在高階像差的解決方案很感興趣。

 class Lam repr where lam :: repr (a,g) b -> repr g (a -> b) app :: repr g (a->b) -> repr g a -> repr g b data Dup repr1 repr2 g a = Dup{d1:: repr1 g a, d2:: repr2 g a} instance (Lam repr1, Lam repr2) => Lam (Dup repr1 repr2) where lam (Dup e1 e2) = Dup (lam e1) (lam e2) app (Dup f1 f2) (Dup x1 x2) = Dup (app f1 x1) (app f2 x2) 
+1

這似乎不太可能。你不能從'(r1,r2) - >(r1,r2)'到'(r1 - > r1,r2 - > r2)'獲得,這將需要實現'Lam(Dup r1 r2)' '(Lam r1,Lam r2)'。 –

+0

@ Li-yaoXia對於任意一個「Monad m」,我認爲從一個'(a - > m b) - > m(a - > b)'是一樣的,直到我讀到第二個鏈接的紙。我支持另一個類似的驚人的解決方案。 – crockeea

+1

@crockeea是一種可以在論文的上下文之外描述的「訣竅」,或者我可以跳到某個頁面以便快速瞭解該如何工作? – jberryman

回答

3

這是不可能的。

要顯示一個例子,我首先做的Lam一個很簡單的例子:

newtype Id a = Id a 

instance Lam Id where 
    lam (Id f) = Id (\x -> let Id r = f x in r) 
    app (Id f) (Id x) = Id (f x) 

現在,我會讓那對Dup小號進行動作的功能:

f :: Dup Id Id Int -> Dup Id Id Int 
f (Dup (Id x) (Id y)) = Dup (Id x*y) (Id y) 

我會,從Lam實例中,能夠做到lam f :: Dup Id Id (Int -> Int)。 這可能看起來像

Dup (Id (\x -> x*y)) (Id (\y -> y)) 

它不能進行,因爲y是不能從x -Lambda。 (使用undefined代替y這裏undefined,拋出運行時錯誤,只要它不能很好地工作。) 這不是一件很少見的事情:任何時候在其他結果中使用其中一個變量時都會發生這種情況。

我不知道你與Monad -generalized一個更強的要求相當的,但這種情況與其他Monad S,太:例如,與Maybe,你不能把以下爲Maybe (Int -> Int),因爲這取決於給定的值:

f :: Maybe Int -> Maybe Int 
f m = m >>= \x -> if x > 5 then Just x else Nothing 

(你可以用它fromJust和希望沒有人這樣做,但它是一樣的undefined的解決方案。)只有

undefined之遙,如果一個錯誤該功能需要t然而,看看其他變量。如果您完全確定它永遠不會運行在這樣的任何事情上(例如,您將展開/創建限制到經過廣泛測試的隱藏模塊),那麼undefined的方式將起作用。

只是多一個建議:使用更詳細的error消息而不是undefined,以防出錯出錯。

0

在模板Haskell做了一些工作後,我有一個適用於這裏的想法。另一種選擇是做TH的方式做:

class Fail.MonadFail m => Quasi m where 
    -- All the things here, like inspecting types, generating names, etc. 
    ... 

-- Many instances, including 
instance Quasi IO where ... -- So you can debug your TH 
instance TH.Quasi GHCiQ where ... -- see https://github.com/ghc/ghc/blob/master/libraries/ghci/GHCi/TH.hs#L167 
instance TH.Quasi TcM where ... -- see https://github.com/ghc/ghc/blob/master/compiler/typecheck/TcSplice.hs#L835 

data Q a = { unQ :: forall m. Quasi m => m a } 
instance Quasi Q where ... 

您可以找到Q單子的定義here

的端用戶工作的Q單子內,並且它可以由任何內部編譯器解釋器,或IO單子進行調試等。任何複製由forall處理進行解釋。你可以,同樣,這樣做

data L a = { unL :: forall repr. Lam repr => repr a } 
instance Lam L where ... 

myEndUserThing :: L ((a -> b) -> a -> b) 
myEndUserThing = lam $ \f -> lam $ \x -> app f x 

很容易轉換到你需要的任何其他repr,如果你需要更多的功能,只需將其添加到Lam類或創建一個額外功能的派生類。