2014-12-06 55 views
6

我偶爾遇到這個問題,最後想問一下是否有一個共同的解決方案或模式。 是否有可能在嵌套上下文引用中創建一個類型變量來自外部上下文的類型?例如,Haskell引用一個類型變量

foo :: a -> ... -> .. 
foo = ... 
    where bar :: a -> ... 

現在bara比富的a不同。通常情況下,這是我想要的,但偶爾它會讓生活變得困難,我需要讓它們變得一樣。我使用骯髒的技巧來迫使類型檢查者在過去統一這兩種技巧,但偶爾也會受到挫折。這是我最新的例子(一個Parsec函數),它激勵我最終提出這個問題。

data Project = ... deriving Enum 
data Stuff = ... 

pProject :: Monad m => P m Stuff 
pProject = do 
    stuff <- pStuff 
    ... 
    convert stuff <$> pEnum :: P m Project 

pEnum :: (Monad m, Enum a) => String -> P m a 
pEnum = ... 

convert函數需要一個類型,因此,我必須指定註釋:: P m Project。 但是,這意味着我還必須介紹m,這不幸與功能簽名中的m不一樣。類型檢查報告,這有:

無法推斷Monad m1從使用pEnum從上下文Monad m

產生有引用函數簽名的m沒有一些醜陋的黑客攻擊的方法嗎?(一個醜陋的黑客是將不會得到執行,但存在只是爲了統一這兩種類型的僞碼。)

回答

13

您正在尋找的ScopedTypeVariables擴展,它可以讓你從包含範圍引用類型變量。

{-# LANGUAGE ScopedTypeVariables #-} 

爲了向下兼容,它僅適用於鍵入具有明確forall簽名。所以,你會寫:

pProject :: forall m. Monad m => P m Stuff 

之後,你會能夠指向正確類型的變量mpProject範圍內。

+5

感謝您指出'ScopedTypeVariables'只適用於具有顯式'forall'的簽名。難怪它似乎幾乎從未工作過...... – Cirdec 2014-12-06 00:51:05

+3

這並不完全正確 - 'ScopedTypeVariables'使類型變量在類聲明中作用域,即使沒有'forall'也是如此。所以它可以改變一個人爲設計的Haskell 2010程序的含義。 – shachaf 2014-12-06 01:52:07