2012-12-07 31 views
4

是否可以提供類型簽名給Haskell值,其中包含用於填充類型推斷算法的「空白」?你可以部分限制Haskell中的類型嗎?

上下文極度做作的例子:

m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

b = isJust m 

這工作。在b使用isJust m約束是Maybe <something>m類型,以及m的定義約束的m類型爲<something> (Char, ((String, String), String, [String], String), String),並且編譯器放在一起的那些信息兩塊制定出的精確類型的m

但是,說我沒有將任何Maybe特定功能應用到m,所以我需要一個手動類型簽名來停止return多態。我不能這樣說:

m :: Maybe a 
m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

因爲這是不正確的。該類型不是Maybe a對於所有的a,它是Maybe a對於一些a我希望編譯器能夠推斷;編譯器有足夠的信息來做到這一點,我們可以從我的第一個例子中看到,編譯器能夠將類型上的多個約束集中在一起,其中沒有單獨的約束就足以找出什麼類型只是在一起,他們完全指定了類型。

我想要的是能夠給類型,如m :: Maybe _,其中_表示「搞清楚到這裏」,而不是「這是一個剛性類型變量」,如m :: Maybe a

有沒有某種方式來說這樣的事情?

m :: Maybe (Char, ((String, String), String, [String], String), String) 
m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

或者到具有約束類型簽名的Maybe一部分,但不是a一樣的效果表達的一部分,給人一種類型簽名:我可以看到明確給出全部類型的選擇:

m = (return :: a -> Maybe a) ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

或離開m沒有一個明確的類型簽名,並引入其約束m未使用額外的定義:

m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

b = isJust m 

或者直接使用單態功能:

m = Just ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

顯然,這是不特定於Maybe,也不至* -> *類型構造函數的參數;我可以想象,如果不想說「這個值是一個monadic Int,對於一些monad」而不想說「這個值是單子Int對於任何 monad」,或者「這是一個從Int到某些其他類型的函數」說:「這是從Int任何其他類型的功能。

我最感興趣的是,是否有一些東西可以讓我直接聲明上述關於值的聲明,以便於閱讀,而不是難以閱讀解決方法(如爲return提供明確的類型簽名)。我知道如果我的目標是簡單地向編譯器中獲取額外的輸入信息來關閉模糊類型變量,那麼有無數的方法可以做到這一點。

+1

[不完整類型簽名]的可能重複(http://stackoverflow.com/questions/11751318/incomplete-type-signature) – hammar

+1

不是[洞](http://hackage.haskell.org/trac/ ghc/wiki/Holes)究竟是否解決了這個問題? – is7s

+0

@ is7s在程序真正起作用之前,仍然需要填充空洞,我認爲對於Haskell來說,它們實際上只是term-level,而不是這裏所需的類型級別。 –

回答

3

對於GHC 7.10,現在有PartialTypeSignatures擴展名,它使我在我的問題中編寫的假設的下劃線語法成爲正確。從文檔範例上面鏈接:

not' :: Bool -> _ 
not' x = not x 
-- Inferred: Bool -> Bool 

maybools :: _ 
maybools = Just [True] 
-- Inferred: Maybe [Bool] 

just1 :: _ Int 
just1 = Just 1 
-- Inferred: Maybe Int 

filterInt :: _ -> _ -> [Int] 
filterInt = filter -- has type forall a. (a -> Bool) -> [a] -> [a] 
-- Inferred: (Int -> Bool) -> [Int] -> [Int] 

只用PartialTypeSignatures擴展編譯器發出警告與推斷出的類型,如果他們只是佔位符,你打算最終版本之前,讓我們填寫。通過添加-fno-warn-partial-type-signatures標誌,您可以告訴它您打算使簽名保持部分。

+1

我寫了並接受了我自己的答案,因爲這正是我3年前所期待的。其他答案對GHC的舊版本仍然非常有用。 – Ben

5

你可以寫類似:

asMaybe :: Maybe a -> Maybe a 
asMaybe = id 

m = asMaybe $ return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

我用這種伎倆在classy-prelude,在提供asByteStringasSetasList

6

GHC不會讓你直接指定部分簽名不幸的是,儘管這樣會很好。

一種方式去做你在這種情況下,想要的是m = return ... `asTypeOf` (undefined :: Maybe a),其中asTypeOf是一個前奏功能:: a -> a -> a返回其第一個參數,但它的力量與第二統一。


這是您在評論中提出的一個要點 - undefined :: SomeType也讓我很難過。這裏是另一種解決方案:

import Data.Proxy 

proxiedAs :: a -> Proxy a -> a 
proxiedAs = const 

現在你可以說m = return ... `proxiedAs` (Proxy :: Proxy (Maybe a)),並且看不到⊥s。

+0

我忘了'asTypeOf'。儘管'undefined :: SomeType'總會讓我有點難過,但這樣會比較好。 – Ben

1

合成邁克爾Snoyman的建議一點,如果我:

  1. 不想有定義每個類型的斷言特定的功能,我想使
  2. 想反倒類型寫接近我是在對
  3. 一種說法不希望有寫類型兩次

我可以這樣做:

type Assert a = a -> a 

m = (id :: Assert (Maybe a)) $ return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 
相關問題