使用 haskell 读取和类型类 - 模棱两可的类型变量错误
Posted
技术标签:
【中文标题】使用 haskell 读取和类型类 - 模棱两可的类型变量错误【英文标题】:Using haskell read and typeclasses - ambiguous type variable error 【发布时间】:2010-06-22 03:01:51 【问题描述】:我在下面的“试用”定义上有一个模棱两可的类型变量错误,我想知道是否有什么办法可以使这种情况起作用?我真的只想处理实例而不是显式数据类型(例如下面包含的 MO1、MO2)。
module Tc102 where
class (Show a, Read a) => MyObj a where
alpha :: a->String
beta :: a->Int
data MO1 = MO1 a1 :: String, b1 :: Int deriving (Show,Read)
data MO2 = MO2 a2 :: String, b2 :: Int deriving (Show,Read)
instance MyObj MO1 where
alpha = a1
beta = b1
instance MyObj MO2 where
alpha = a2
beta = b2
a = MO1 "a" 3
b = MO2 "b" 4
test :: MyObj a => a->String
test = alpha
showMe :: (MyObj a)=> a -> String
showMe = show
readMe :: (MyObj a) => String -> a
readMe = read
trial :: MyObj a => a -> String
trial = test . readMe . showMe
提前谢谢大家!但是我担心我可能需要使用一个辅助函数,将旧 ADT 转换为“最新版本”......
西蒙
编辑为了澄清,假设我首先显示到文件,然后重新加载对象。那么我拥有的功能更像
trial :: String -> Int
trial s = beta x
where x = readMe s
【问题讨论】:
【参考方案1】:您收到错误是因为编译器不知道readMe
应该返回什么具体类型,因为test
所要求的只是它是MyObj
的一个实例。它可以是 MO1
、MO2
或其他完全不同的东西,readMe
可以返回其中任何一个。
假设您希望 readMe . showMe
像 id
一样工作并输出与输入相同的类型,快速而简单的方法是定义一个函数来完成此操作,并为其指定一个类型签名,该签名等同于输入输出类型:
trial :: MyObj a => a -> String
trial = test . readShowMe
where readShowMe :: MyObj a => a -> a
readShowMe = readMe . showMe
现在编译器可以确定将什么具体类型提供给test
作为输入。
【讨论】:
啊,当示例出错时,您不只是喜欢它,请查看原始帖子以获得澄清! :) 尽管我仍然相信您评论的第一部分仍然是问题所在。很遗憾,鉴于类型类信息和字符串格式,运行时无法确定 obj 是 MO1 等......【参考方案2】:您无法从运行时文件中读取编译时类型。您应该显式地实现运行时类型变化的值。
例如:
data AnyMyObj = forall a . MyObj a => AnyMyObj a
test :: AnyMyObj -> String
test (AnyMyObj x) = alpha x
showMe :: AnyMyObj -> String
showMe (AnyMyObj x) = show x
readMe :: String -> AnyMyObj
readMe s = AnyMyObj (read s :: MO1) -- maybe something more complicated
trial :: AnyMyObj -> String
trial = test . readMe . showMe
【讨论】:
有了更多的type-foo,得到了一些应该工作的东西。谢谢!【参考方案3】:这有很多花哨的技巧,最终的答案确实是读入某种存在主义。有关执行此操作的非常强大/通用方法的精彩说明,请参阅 Oleg 的无类型标签最终讲义:http://okmij.org/ftp/tagless-final/course/#type-checking。
但是对于像你这样的例子来说,这太夸张了——当你有树结构时,特别是当你有代表 lambda 项的树结构时,通常会出现棘手的问题。
出于您的目的,上面的示例大致正确。
但请记住,即使您可以创建新的 MyObj 实例,您的 read 函数也只能读取固定的 Universe,至少无需高级黑客。
所以在这种情况下,我会质疑您是否希望以类型类开头,或者只是在单个 ADT 中使用更多构造函数。
data MyObj = MO1 a1 :: String, b1 :: Int
| MO2 a2 :: String, b2 :: Int deriving (Show,Read)
...例如。
【讨论】:
以上是关于使用 haskell 读取和类型类 - 模棱两可的类型变量错误的主要内容,如果未能解决你的问题,请参考以下文章
在 Haskell 中编写 AI Solver 时的类型变量不明确
将抽象数据类型保存和加载到 json 文件并从游戏中的文件中读取 Haskell