在 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 或反射恶作剧,只需将您的 Add
和 Sub
案例合并为一个:
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?