从字符串转换为类型值

Convert to typed value from String

我有一个包含值和类型列表的文件,在阅读它们之后我需要将它们放入数据库中。为此,我需要为插入函数提供正确类型的元组,所以我试图用这样的东西转换值

toProperType :: String -> String -> a  
toProperType tp val =
  case tp of
    "string" -> val            -- ::String
    "int"    -> toIntType val  -- ::Int64
    "bigint" -> toIntType val  -- ::Int64
    "integer"-> toIntType val    
    "utcdate"-> toDateType val -- :: UTCTime
    "double" -> toDoubleType val -- :: Double

失败

Couldn't match expected type ‘a’ with actual type ‘Double’ ‘a’ is a rigid type variable bound by

我认为是正确的。

实现此功能的正确方法是什么?

也许我需要一些扩展或使用 TH 生成单独的函数(但不确定如何调度它们)

这里的问题是 -> a 在你的函数类型中的含义。如果你的函数实际上有这种类型,那么 调用 你的函数的人应该能够指定他们选择的具体类型(你甚至可能不在范围内)然后期待你的功能就像它具有类型

一样工作
String -> String -> MyCustomType

但这显然不是您的初衷。你不是说"for all types a, I have a function ...",你是说"For any two strings, there is some type a for which I have a value"。这个想法,你可以选择类型变量而不是调用者,被称为 "existential quantification" 并且 GHC 确实支持它。但是我真的不认为那是你想要做的。毕竟,当您实际使用此函数时,您可能希望能够判断是否返回了 UTCTimeDouble 之类的东西。因为你不能用存在量化来做到这一点(就像你不能在多态函数中对类型变量进行大小写一样)我们应该创建一个自定义数据类型:

data Dyn = String String | Int Int | BigInt Integer | UTCDate UTCTime ...

等等。也就是说,您为您的类型可能 return 的每种情况列出一个显式构造函数,然后您的函数将读取

toProperType :: String -> String -> Dyn  
toProperType tp val =
  case tp of
    "string" -> String val            -- ::String
    "int"    -> Int $ toIntType val  -- ::Int64
    "bigint" -> BigInt $ toIntType val  -- ::Int64
    "integer"-> Integer $ toIntType val    
    "utcdate"-> UTCDate $ toDateType val -- :: UTCTime
    "double" -> Double $ toDoubleType val -- :: Double

这就是 Haskell 库处理诸如 JSON 解析之类的事情的严肃程度,所以你们是好伙伴。现在它的类型很好,调用此函数的人只是根据 Dyn 值计算大小写,并根据 returned 类型决定要做什么。