Haskell 从字符串转换为类型化值

Haskell 从字符串转换为类型化值,haskell,generic-programming,template-haskell,Haskell,Generic Programming,Template Haskell,我有一个包含值和类型列表的文件,在读取它们之后,我需要将它们放入数据库中。为此,我需要为插入函数提供正确类型的元组,所以我尝试用类似这样的方法转换值 toProperType :: String -> String -> a toProperType tp val = case tp of "string" -> val -- ::String "int" -> toIntType val -- ::Int64

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

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
这是失败的

无法将预期类型“a”与实际类型“Double”匹配 “a”是一个刚性类型变量,由

我认为这是正确的

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


可能我需要一些扩展或使用TH生成单独的函数(但不确定如何分派它们)

这里的问题是函数类型中
->a
的含义。如果您的函数实际上具有这种类型,那么调用您的函数的人应该能够指定他们选择的具体类型(您甚至可能在作用域中都没有),然后期望您的函数像具有这种类型一样工作

String -> String -> MyCustomType
然而,这显然不是你想要的。您的意思不是“对于所有类型
a
,我都有一个函数…”,而是“对于任何两个字符串,都有某个类型
a
,我有一个值”。您可以选择类型变量而不是调用者,这种想法被称为“存在量化”,GHC确实支持它。但是我真的不认为那是你想要做的。毕竟,当您实际使用此函数时,您可能希望能够对是否返回了
UTCTime
Double
或其他内容进行分析。由于无法使用存在量化实现这一点(就像无法对polymoprhic函数中的类型变量进行装箱一样),因此我们应该创建一个自定义数据类型:

data Dyn = String String | Int Int | BigInt Integer | UTCDate UTCTime ...
等等。也就是说,您为您的类型可能返回的每种情况列出一个显式构造函数,然后您的函数将读取

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
值进行case运算,并根据返回的类型决定要执行的操作。

正如编译器告诉您的那样,您的函数是真正的泛型函数-它声称可以返回任何类型
a
,但您继续,您的case返回非常特定的类型。。。所以编译器抱怨。第一步是尝试并找出结果的共同点-这里您希望能够将它们放入某种数据库(您没有写任何东西)-因此,我的第一次尝试是返回一个函数,给定db上下文将把值写入其中:
makepersistence::String->String->(DbContext->IO())
顺便说一句:返回一条SQL语句,表示将
INSERT
插入数据库(假设它是某种SQL-DB)可能就足够了,因此它也可以是
String->String->String
,您可能更容易看到-比如
case-tp of“String”->“INSERT-into-table-VALUES(”++val++“”)“
(当然我觉得我必须告诉你,这可能真的很危险,因为它为SQL注入attacs打开了大门)我有PostgreSQL,并试图用类似于
res:(或者某个异常[Only Int])的东西插入(使用我给你的第一个想法替换
DbContext->IO()
无论您的
查询'
将使用哪种类型,您都可以创建一个
数据MyValue=IntVal Int64 | StrVal String | FloVal Double | TimeVal UTVTime
并返回该类型。然后,插入函数可以在该类型上进行模式匹配。