[英]Pattern Matching on Promoted Types
我們可以為類型參數*
編寫單個,全面的實例:
class MyClass d where
f :: d -> Int
instance MyClass (Maybe d) where
f _ = 3
test1 :: Maybe d -> Int
test1 x = f x
編譯得很好,並注意我們在test1上不需要(MyClass(Maybe d))約束,因為編譯器找到任何Maybe d
的匹配實例。
我們甚至可以為類型構造函數的類參數編寫一個包羅萬象的實例:
class MyClass2 (a :: * -> *) where
g :: Tagged (a Int) Int
instance MyClass2 a where
g = Tagged 3
test2 :: Int
test2 = untag (g :: Tagged (Maybe Int) Int)
這也編譯得很好,而test2不需要(MyClass2 Maybe)約束,因為編譯器找到了匹配的實例。
考慮以下玩具代碼來計算(提升的)類型列表的長度:
{-# LANGUAGE TypeOperators,
DataKinds,
KindSignatures,
GADTs,
FlexibleInstances,
FlexibleContexts,
ScopedTypeVariables #-}
import Data.Tagged
import Data.Proxy
data HList :: [*] -> * where
HNil :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
class ListLen a where
len :: Tagged a Int
instance ListLen (HList '[]) where
len = Tagged 0
instance (ListLen (HList as)) => ListLen (HList (a ': as)) where
len = Tagged (1+(untag (len :: Tagged (HList as) Int)))
test3 :: Int
test3 = untag (len :: Tagged (HList '[Int, Double, Integer]) Int)
test4 :: (Proxy (HList qs)) -> Int
test4 (_ :: Proxy (HList qs)) = untag (len :: Tagged (HList qs) Int) -- error occurs here
這會導致錯誤:
No instance for (ListLen (HList qs))
arising from a use of `len'
Possible fix: add an instance declaration for (ListLen (HList qs))
...
如果我們注釋掉test4
的簽名,GHCi會將類型推斷為
test4 :: (ListLen (HList qs)) => (Proxy (HList qs)) -> Int
但這不應該是必要的 。 顯然,我已經為ListLen
編寫了匹配任何可想到的類型列表的實例:“空列表”案例和“缺點”案例。 如果我將ListLen
參數的類型更改為kind [*]
(即,刪除ListLen
及其實例中的HList
包裝器),問題仍然存在。
如果我們注釋掉test4
, test3
編譯並運行正常:因為我(基本上)為我如何構造類型列表給出了顯式語法( '[Int,Double,Integer]
),編譯器能夠找到匹配的實例。
我正在嘗試編寫為我構建類型列表的代碼,因此我不必寫出顯式類型列表語法。 但是,似乎使用顯式語法是GHC能夠匹配這些綜合實例的唯一方法。 也許有一個我失蹤的案子? 語法我沒用?
我能做些什么才能讓GHC意識到我有一個實例[*]
? 我正在使用GHC 7.4.2。 這可能與之前關於解構非推廣類型的帖子有關。 上式推廣,紙可以找到這里 。
這不是你想要的,但是非常接近。 我開始了
data Proxy a where
Proxy :: ListLen a => Proxy
然后
data Proxy a where
Proxy :: Tagged a Int -> Proxy a
導致
test4 :: (Proxy (HList qs)) -> Int
test4 (Proxy len) = untag len
問題是您要么需要約束,要么讓Proxy
包含所需類的證據(即使所有可用種類都存在實例)。 這里,類方法只包含在Proxy
。
一個完全不同的選擇是根本不使用類型類,並以通常的方式實現len
(從Data.List.length
轉錄)。
len :: HList a -> Int
len l = len' l 0
where
len' :: HList a -> Int -> Int
len' HNil a = a
len' (HCons _ xs) a = len' xs $! a + 1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.