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