用相应的符号标记字符串

时间:2014-05-30 19:40:06

标签: haskell types gadt

我想要一种简单的方法来创建一个用自己标记的String。现在我可以 做类似的事情:

data TagString :: Symbol -> * where
    Tag :: String -> TagString s
    deriving Show

tag :: KnownSymbol s => Proxy s -> TagString s
tag s = Tag (symbolVal s)

并像

一样使用它
tag (Proxy :: Proxy "blah")

但这并不好,因为

  • 有关标记的保证仅由tag提供,而非由GADT提供。
  • 每次我想创建一个值时,我都必须提供一个类型签名 如果价值是一些更大的表达的一部分,那就变得笨拙。

有没有办法改善这一点,最好是朝着相反的方向,即从StringSymbol?我想写Tag "blah"并让ghc推断出类型 TagString "blah"

GHC.TypeLits提供了someSymbolVal函数 相关,但它产生SomeSymbol,而不是Symbol,我可以很好地掌握如何使用 它

1 个答案:

答案 0 :(得分:8)

  

有没有办法改善这一点,最好是朝相反的方向,即从字符串到符号?

无法直接从String转到Symbol,因为不幸的是,Haskell并非依赖类型。每次想要一个新值时,你都必须写出一个类型注释,并且没有一个带有所需符号的现有标签。

  

标签的保证仅由标签提供,而不是由GADT提供。

以下内容应该运行良好(实际上,singletons包中可以找到相同的类型):

data SSym :: Symbol -> * where
    SSym :: KnownSymbol s => SSym s

-- defining values
sym1 = SSym :: SSym "foo"
sym2 = SSym :: SSym "bar"

这种类型与Proxy的不同之处仅在于构造函数中包含KnownSymbol字典。字典让我们恢复包含在其中的字符串,即使该符号不是静态知道的:

extractString :: SSym s -> String
extractString s@SSym = symbolVal s 

我们在SSym上匹配模式,从而将隐式KnownSymbol字典纳入范围。仅使用Proxy

同样不起作用
extractString' :: forall (s :: Symbol). Proxy s -> String
extractString' p@Proxy = symbolVal p 
-- type error, we can't recover the string from anywhere
  

...它产生一个SomeSymbol,而不是一个符号,我可以完全掌握如何使用它。

SomeSymbolSSym类似,只是它隐藏了它所带的字符串,因此它不会出现在该类型中。可以通过构造函数上的模式匹配来恢复字符串。

extractString'' :: SomeSymbol -> String
extractString'' (SomeSymbol proxy) = symbolVal proxy

当您想要批量操作不同的符号时,它会很有用,例如,您可以将它们放在一个列表中(您可以使用不同的SSym - s,因为它们的类型不同)