在Gadt中进行模式匹配时,绑定类型变量最直接的方法是什么?
#!/usr/bin/env stack
-- stack script --resolver lts-13.1
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}
module Main where
import Data.Proxy
import GHC.TypeLits
main :: IO ()
main = undefined
data Kind where
Index :: Symbol -> Kind
data Gadt (f::Kind) where
Lit :: KnownSymbol s => Gadt ('Index s)
直接绑定s
会失败
format :: Gadt f -> String
format (Lit :: Gadt ('Index s)) = undefined -- KO
有错误
• Couldn't match type ‘f’ with ‘'Index s’
‘f’ is a rigid type variable bound by
the type signature for:
format :: forall (f :: Kind). Gadt f -> String
Expected type: Gadt f
Actual type: Gadt ('Index s)
类型函数可以提取类型,但是没有更直接的方法吗?
format (Lit :: Gadt i) = symbolVal (Proxy :: TLabel i)
type family TLabel (a::Kind)
type instance TLabel ('Index s ) = Proxy s
答案 0 :(得分:3)
我看到的唯一方法是添加一个Proxy
以将类型变量与ScopedTypeVariables
绑定。
data Gadt a where
Lit :: KnownNat s => Proxy s -> Gadt ('Index s)
format :: Gadt a -> String
format (Lit (Proxy :: Proxy s)) = undefined
如果您担心额外的分配,可以将字段拆开。 (编辑:删除了先前对Proxy#
的提及,因为这似乎没有必要。)
import Data.Proxy
-- This should be as efficient as the original Gadt with a nullary Lit
data Gadt a where
Lit :: {-# UNPACK #-} !(Proxy r) -> Gadt ('Index r)
format :: Gadt a -> String
format (Lit (_ :: Proxy r)) = undefined
从长远来看,以下GHC提案将解决此问题:Type Applications in Patterns。
-- The original type
data Gadt a where
Lit :: forall s. Gadt ('Index s)
format :: Gadt a -> String
format (Lit @s) = ...