使用 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 的一个实例。它可以是 MO1MO2 或其他完全不同的东西,readMe 可以返回其中任何一个。

假设您希望 readMe . showMeid 一样工作并输出与输入相同的类型,快速而简单的方法是定义一个函数来完成此操作,并为其指定一个类型签名,该签名等同于输入输出类型:

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 模棱两可的出现——如何避免?

在 Haskell 中编写 AI Solver 时的类型变量不明确

为什么Haskell说这是模棱两可的?

将抽象数据类型保存和加载到 json 文件并从游戏中的文件中读取 Haskell

在没有更多上下文的情况下,表达式的类型是模棱两可的。 <SocketEngine> 类

Haskell 多态性和类型类实例