我想要一种简单的方法来创建一个用自己标记的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提供。有没有办法改善这一点,最好是朝着相反的方向,即从String
到Symbol
?我想写Tag "blah"
并让ghc推断出类型
TagString "blah"
。
GHC.TypeLits提供了someSymbolVal
函数
相关,但它产生SomeSymbol
,而不是Symbol
,我可以很好地掌握如何使用
它
答案 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,而不是一个符号,我可以完全掌握如何使用它。
SomeSymbol
与SSym
类似,只是它隐藏了它所带的字符串,因此它不会出现在该类型中。可以通过构造函数上的模式匹配来恢复字符串。
extractString'' :: SomeSymbol -> String
extractString'' (SomeSymbol proxy) = symbolVal proxy
当您想要批量操作不同的符号时,它会很有用,例如,您可以将它们放在一个列表中(您可以使用不同的SSym
- s,因为它们的类型不同)