【问题标题】:Using haskell read and typeclasses - ambiguous type variable error使用 haskell 读取和类型类 - 模棱两可的类型变量错误
【发布时间】: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

【问题讨论】:

    标签: haskell instance typeclass


    【解决方案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)
    

    ...例如。

    【讨论】:

      猜你喜欢
      • 2012-12-18
      • 2012-10-18
      • 1970-01-01
      • 2010-09-30
      • 2018-10-25
      • 1970-01-01
      • 1970-01-01
      • 2011-07-23
      相关资源
      最近更新 更多