简体   繁体   English

提升类型的模式匹配

[英]Pattern Matching on Promoted Types

We can write single, comprehensive instances for parameters of kind * : 我们可以为类型参数*编写单个,全面的实例:

class MyClass d where
    f :: d -> Int

instance MyClass (Maybe d) where  
    f _ = 3

test1 :: Maybe d -> Int
test1 x = f x

This compiles just fine, and note that we do NOT need a (MyClass (Maybe d)) constraint on test1 because the compiler finds a matching instance for any Maybe d . 编译得很好,并注意我们在test1上不需要(MyClass(Maybe d))约束,因为编译器找到任何Maybe d的匹配实例。

We can even write an all-encompassing instance for class parameters that are type constructors: 我们甚至可以为类型构造函数的类参数编写一个包罗万象的实例:

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)

This also compiles fine, and test2 does not need a (MyClass2 Maybe) constraint, because the compiler finds a matching instance. 这也编译得很好,而test2不需要(MyClass2 Maybe)约束,因为编译器找到了匹配的实例。

Consider the following toy code to compute the length of a (promoted) type list: 考虑以下玩具代码来计算(提升的)类型列表的长度:

{-# 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

This results in the error: 这会导致错误:

No instance for (ListLen (HList qs))
      arising from a use of `len'
    Possible fix: add an instance declaration for (ListLen (HList qs))
    ...

If we comment out the signature for test4 , GHCi infers the type as 如果我们注释掉test4的签名,GHCi会将类型推断为

test4 :: (ListLen (HList qs)) => (Proxy (HList qs)) -> Int

but this shouldn't be necessary . 但这不应该是必要的 Clearly, I've written instances for ListLen that match any conceivable type list: an 'empty list' case, and a 'cons' case. 显然,我已经为ListLen编写了匹配任何可想到的类型列表的实例:“空列表”案例和“缺点”案例。 The problem remains the same if I change the kind of the ListLen parameter to have kind [*] (ie, remove the HList wrapper in ListLen and its instances). 如果我将ListLen参数的类型更改为kind [*] (即,删除ListLen及其实例中的HList包装器),问题仍然存在。

If we comment out test4 , test3 compiles and runs fine: since I (essentially) gave it explicit syntax ( '[Int,Double,Integer] ) for how I constructed the type list, the compiler was able to find matching instances. 如果我们注释掉test4test3编译并运行正常:因为我(基本上)为我如何构造类型列表给出了显式语法( '[Int,Double,Integer] ),编译器能够找到匹配的实例。

I'm attempting to write code that builds a type list for me, so I will not have to write out the explicit type list syntax. 我正在尝试编写为我构建类型列表的代码,因此我不必写出显式类型列表语法。 However, it seems that using explicit syntax is the only way GHC is able to match these comprehensive instances. 但是,似乎使用显式语法是GHC能够匹配这些综合实例的唯一方法。 Perhaps there's a case I'm missing? 也许有一个我失踪的案子? Syntax I'm not using? 语法我没用?

What can I do to make GHC realize that I have an instance for everything of kind [*] ? 我能做些什么才能让GHC意识到我有一个实例[*] I'm using GHC 7.4.2. 我正在使用GHC 7.4.2。 This might be related to a previous post about deconstructing non-promoted types. 可能之前关于解构非推广类型的帖子有关。 THE paper on type promotion can be found here . 上式推广,纸可以找到这里

This is not exactly what you want, but gets pretty close. 这不是你想要的,但是非常接近。 I started out with 我开始了

data Proxy a where
  Proxy :: ListLen a => Proxy

then 然后

data Proxy a where
  Proxy :: Tagged a Int -> Proxy a

resulting in 导致

test4 :: (Proxy (HList qs)) -> Int
test4 (Proxy len) = untag len

The problem is you either need to have the constraint, or have Proxy contain evidence of the required class (even though instances exist for all available kinds). 问题是您要么需要约束,要么让Proxy包含所需类的证据(即使所有可用种类都存在实例)。 Here, the class method is just included in Proxy . 这里,类方法只包含在Proxy

A completely different option is to just not use a type class at all, and implement len in the usual way (transcribed from Data.List.length ). 一个完全不同的选择是根本不使用类型类,并以通常的方式实现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