代码之家  ›  专栏  ›  技术社区  ›  Simon P

使用haskell read和typeclasses-类型变量不明确错误

  •  1
  • Simon P  · 技术社区  · 15 年前

    我有一个含糊不清的类型变量错误的定义“审判”下面,我想知道是否有什么可以做,使这种情况下的工作?我只想处理实例,而不是显式的数据类型(比如下面包含的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
    

    西蒙

    编辑 为了澄清这一点,假设我首先显示一个文件,然后重新加载对象。我的功能更像

    trial :: String -> Int
    trial s = beta x
      where x = readMe s
    
    3 回复  |  直到 15 年前
        1
  •  0
  •   ony    15 年前

    无法从运行时文件读取编译时类型。应该显式实现运行时类型可变值。

    例如:

    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
    
        2
  •  1
  •   Paul Kuliniewicz    15 年前

    你得到这个错误是因为编译器不知道具体的类型是什么 readMe 应该回来,因为 test 要求它是的实例 MyObj MO1 MO2 ,或者完全其他的东西 自述 可以归还任何一个。

    readMe . showMe id 和输出作为输入给定的相同类型,快速而肮脏的方法是定义一个函数来实现这一点,并给它一个等同于输入和输出类型的类型签名:

    trial :: MyObj a => a -> String
    trial = test . readShowMe
        where readShowMe :: MyObj a => a -> a
              readShowMe = readMe . showMe
    

    测试 作为输入。

        3
  •  0
  •   sclv    15 年前

    http://okmij.org/ftp/tagless-final/course/#type-checking .

    就你的目的而言,ony上面的例子大致正确。

    但是请记住,即使您可以创建MyObj的新实例,您的read函数也只能读取一个固定的宇宙,至少在没有高级黑客的情况下是这样的。

    所以在这种情况下,我想问你是想要一个typeclass开始,还是仅仅在一个ADT中有更多的构造函数。

    data MyObj = MO1 { a1 :: String, b1 :: Int }
               | MO2 { a2 :: String, b2 :: Int } deriving (Show,Read)
    

    ... 例如。