使用haskell read和typeclasses - 模糊类型变量错误

时间:2010-06-22 03:01:52

标签: haskell instance typeclass

我在下面的“试用”定义中有一个模糊的类型变量错误,我想知道是否有任何可以做的事情来使这种情况起作用?我想真正处理实例而不是明确的数据类型(例如下面包含的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

3 个答案:

答案 0 :(得分: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作为输入提供的具体类型。

答案 1 :(得分:0)

您无法从运行时文件中读取编译时类型。您应该明确实现运行时类型变化值。

例如:

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 :(得分:0)

对此有一些奇特的伎俩,最终的答案确实是要读到某种存在主义。有关这种非常强大/通用的方法的幻想,请参阅Oleg的Typed-tagless最终讲义:http://okmij.org/ftp/tagless-final/course/#type-checking

但是对于像你这样的例子来说,这是一种严重的矫枉过正 - 当你有树结构时,特别是当你的树结构代表lambda术语时,通常就会进入棘手状态。

出于您的目的,上面的示例大致正确。

但请记住,即使您可以创建MyObj的新实例,您的读取函数也只能读取固定的Universe,至少没有高级别的hackery。

所以这是一个我要问你是否想要一个类型类开头,或者只是在一个ADT中有更多构造函数的情况。

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

......例如。