在 Haskell 中将字符串转换为类型构造函数

Posted

技术标签:

【中文标题】在 Haskell 中将字符串转换为类型构造函数【英文标题】:Convert a String to a Type Constructor in Haskell 【发布时间】:2011-12-31 05:00:21 【问题描述】:

有谁知道 Haskell 中是否有这样的功能:

"Int" -> Int

"String" -> String

"Bool" -> Bool

即。它采用类型构造函数名称的字符串表示形式,并将其转换为实际的类型构造函数,无论是在表达式中还是在模式中。

编辑: 我的总体目标是简化以下内容:

transExp (Add exp1 exp2) vars
  = transExp exp1 vars ++ transExp exp2 vars ++ [IAdd]

transExp (Sub exp1 exp2) vars
  = transExp exp1 vars ++ transExp exp2 vars ++ [ISub]

变成一个单一的模式匹配,所以基本上把Add或者Sub转换成一个字符串,在前面加一个“I”,然后再转换回一个类型。

【问题讨论】:

这可能吗?类型不是编译时概念吗?您正在寻找的功能是什么类型的? 我不知道这是否可能,我想它的类型是 String -> a,但我真的不确定...... 然后看看模板haskell。此外,IAdd 不是类型,而是类型构造函数——这具有误导性。 查看您的示例,您似乎不想将字符串转换为类型构造函数,但您想将其转换为值构造函数。这可能使用read ("I" ++ x) 来实现。但不要这样做!如果您使用字符串在不同类型之间进行转换,则会出现问题。 【参考方案1】:

在什么情况下?有 Template Haskell 和 Data.Typeable,但要获得真正有用​​的答案,您需要提供更多详细信息。

【讨论】:

【参考方案2】:

好吧,问题来了。

"String" -> String

这在 Haskell 领域是胡言乱语,因为 "String" 是一个值,而 String 是一个类型。所以你可以试试这个:

String -> a

这不符合您的要求。您应该学习如何阅读类型签名,因为如果您无法阅读类型签名,那么您将在 Haskell 中受到严重影响。上述类型的意思是,“给我一个字符串,我可以给你一个你要求的任何类型的值。”前奏中有一个函数有这个签名,叫error,不是你想要的。

听起来你想要一些类似的东西:

String -> TypeRep

抱歉,没有这个功能。 TypeRep 不实例化 Read 类。

实际上想在这里做什么?如果你告诉我们你真正想做什么,我们可以帮助你解决这个问题,而不是试图帮助遇到这个问题。

【讨论】:

他不是在谈论类型名称,而是在谈论类型构造函数。他只想从字符串中生成一些值和模式匹配以避免样板。 @nponeccop:在问题发生变化后对答案投反对票并不完全公平。这个关于构造函数的业务是全新的。【参考方案3】:

你不能这样做,因为字符串是运行时数据,类型必须在编译时完全解析。你可以用你的例子做的最好的事情是一个帮助函数来消除一些重复:

helper exp1 exp2 vars op = transExp exp1 vars ++ transExp exp2 vars ++ [op]
transExp (Add exp1 exp2) vars = helper exp1 exp2 vars IAdd
transExp (Sub exp1 exp2) vars = helper exp1 exp2 vars ISub

但从长远来看,这实际上可能不是很有用,具体取决于您拥有多少案例。

通常,模式匹配是针对类型结构运行的,因此必须在编译类型时针对具体类型构造函数进行说明。这是拥有真正可靠的静态类型系统所必须付出的代价。

【讨论】:

他可以使用在编译时运行的模板 Haskell 代码来做到这一点 确实可以,但出于他所说的目的,这对我来说似乎有点矫枉过正。 我认为他必须知道所有可能的解决方案。这是他了解 TH 能做什么的好机会。 @hammar 解决方案也很棒。【参考方案4】:

有一种更好的方法可以在这里重构您的代码,而无需任何模板 Haskell 或反射恶作剧,只需将您的 AddSub 案例合并为一个:

data BinOp = Add | Sub | ...

data Expr = ...
          | BinOp BinOp Expr Expr
          | ...

transExp (BinOp op exp1 exp2) vars
    = transExp exp1 vars ++ transExp exp2 vars ++ [transOp op]
...

transOp Add = IAdd
transOp Sub = ISub

这样,我们使用数据类型直接表达二元运算符相关的事实,因此具有相似的翻译。如果您想在某处添加特殊情况,您仍然可以在 BinOp Add exp1 exp2 上进行模式匹配。

【讨论】:

很棒的解决方案 - 比我想象的要简单得多。非常感谢:) 这要优雅得多。感谢您提醒我们再次缩小并获得更广阔的视野会有所帮助。

以上是关于在 Haskell 中将字符串转换为类型构造函数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用“ord”函数在 Haskell 中将 Char 转换为 Int?

在 Haskell 中将字符串转换为整数/浮点数?

在haskell中将整数列表转换为一个Int(如concat)

如何在 haskell 中打印列表?

JavaScript中将字符串类型转换为整形的函数

重新格式化 Haskell 数据构造函数类型程序并重新格式化