繁体   English   中英

GADT的类型推断

[英]Type inference with GADTs

在以下代码中,我尝试在GADT构造函数Cons上进行匹配,以使编译器看到xs为非空:

{-# LANGUAGE DataKinds           #-} 
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE KindSignatures      #-} 
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators       #-}

import Data.Typeable

data Foo (ts :: [*]) where
  Nil :: Foo '[]
  Cons :: (Typeable t) => Foo ts -> Foo ( t ': ts)

foo :: Foo xs -> IO ()
foo Nil = print "done"
foo (Cons rest :: Foo (y ': ys)) = do
  print $ show $ typeRep (Proxy::Proxy y)
  foo rest

不幸的是,这个简单的示例无法使用GHC 8进行编译:

• Couldn't match type ‘xs’ with ‘y : ys’
  ‘xs’ is a rigid type variable bound by
    the type signature for:
      foo :: forall (xs :: [*]). Foo xs -> IO ()
  Expected type: Foo (y : ys)
    Actual type: Foo xs
• When checking that the pattern signature: Foo (y : ys)
    fits the type of its context: Foo xs
  In the pattern: Cons rest :: Foo (y : ys)
  In an equation for ‘foo’:
      foo (Cons rest :: Foo (y : ys))
        = print $ (show $ typeRep (Proxy :: Proxy y))

我知道使用GADT(例如#9695#10195#10338 )可能很难进行类型推断,但这简单...

我应该怎么做才能说服GHC:当我在Cons匹配时,GADT参数至少包含一个元素?

您只需要一个从Foo (t ': ts)提取Proxy t的函数:

fooFstType :: Foo (t ': ts) -> Proxy t 
fooFstType _ = Proxy 

请注意,由于Foo的类型参数是t ': ts ,而不是ts ,因此您可以引用表示类型签名中第一个元素的类型变量(而不是主体中的ScopedTypeVariables )。

您的功能变为

foo :: Foo xs -> IO ()
foo Nil = print "done"
foo f@(Cons rest) = do
  print $ show $ typeRep (fooFstType f)
  foo rest

另一种可能性是将工作移到类型级别:

type family First (xs :: [k]) :: k where 
  First (x ': xs) = x 

foo :: forall xs . Foo xs -> IO ()
foo Nil = print "done"
foo (Cons rest) = do
  print $ show $ typeRep (Proxy :: Proxy (First xs))
  foo rest

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM