簡體   English   中英

提升類型的模式匹配

[英]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包裝器),問題仍然存在。

如果我們注釋掉test4test3編譯並運行正常:因為我(基本上)為我如何構造類型列表給出了顯式語法( '[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM