【问题标题】:Type class polymorphism with overloaded numeric and string literals具有重载数字和字符串文字的类型类多态性
【发布时间】:2018-04-03 23:13:48
【问题描述】:

我正在尝试编写一些 EDSL 来为键分配值。所以我有以下数据类型的值:

data Value = B Bool | I Int

我希望有统一的方式将不同的值转换为Value 类型的对象。所以我创建了以下类型类:

class    ToValue a    where toValue :: a -> Value
instance ToValue Bool where toValue = B
instance ToValue Int  where toValue = I

很遗憾,这段代码无法编译:

foo :: [Value]
foo = [toValue True, toValue 3]

我明白原因。但这让我很难过。我真的不明白如何解决这个问题......如果我启用了-XOverloadedStrings 并且我想将T Text 构造函数添加到我的Value 类型,事情会变得更加困难。

我的最终目标是有能力写出这样的东西:

foo :: [(Text, Value)]
foo = [ "key1" !!! True
      , "key2" !!! 42
      , "key3" !!! "foo"
      , "key4" !!! [5, 7, 10]
      ]

我知道我总是可以手动将每个值包装到相应的构造函数中,但我宁愿避免这种情况(因为在我的现实生活中构造函数比一个字母长,并且代码并没有真正减少构造函数的噪音)。

我可以做些什么来实现最接近的实现?如果可能的话,我想避免Value 的不安全Num 实例...

【问题讨论】:

  • 原来ExtendedDefaultRules 工作。出于某种原因,我认为这是 GHCi 独有的东西。

标签: haskell polymorphism overloading typeclass


【解决方案1】:

使用ExtendedDefaultRules。 (在 GHCi 中默认启用,在 GHC 中使用 pragma 启用。)

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}

default (Int, String)

class Value a where
  toValue :: a -> String

instance Value Int where
  toValue = show

instance Value String where
  toValue = id

main = do
  print (toValue 3)    -- would otherwise be ambiguous
  print (toValue "x")

旧答案

如果我理解正确,这里的目标是保持语法统一,同时适当地专门化文字。一种方法是使用 Template Haskell,所以 foo 可能看起来像

foo = [$(toValue [|True|]), $(toValue [|3|])]

foo = [ [toValue| True |], [toValue| 3 |] ]  

后者不那么费钱,但实现自定义报价需要表达式解析器,而 template-haskell 没有提供。

【讨论】:

  • 编译器插件将是解决此问题的另一种方法,但我不知道如何编写。
  • 感谢您的回答!很好的建议:+1:我有编写 ghc 插件的经验。这并不是一个人真正想做的事情......-XExtendedDefaultRules 的解决方案对我来说已经相当不错了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-03
  • 2017-06-30
  • 2018-12-24
相关资源
最近更新 更多