Haskell Can';t正确定义通用类型的转换,即用GADT定义的转换
我已经定义了一个可以包含任何内容的通用数据类型(好吧,在当前的实现中不是完全包含任何内容) 这是(完整代码): 我可以在控制台中使用它:Haskell Can';t正确定义通用类型的转换,即用GADT定义的转换,haskell,ghc,gadt,Haskell,Ghc,Gadt,我已经定义了一个可以包含任何内容的通用数据类型(好吧,在当前的实现中不是完全包含任何内容) 这是(完整代码): 我可以在控制台中使用它: *Main> a [Any "Hahaha",Any 123] it :: [AnyT] *Main> readAnyT (read::String->Float) "134" Any 134.0 it :: AnyT *Main> showAnyT $ Any 125 "125" it :: String 嗯,我有,但我需要以某种
*Main> a
[Any "Hahaha",Any 123]
it :: [AnyT]
*Main> readAnyT (read::String->Float) "134"
Any 134.0
it :: AnyT
*Main> showAnyT $ Any 125
"125"
it :: String
嗯,我有,但我需要以某种方式处理它。例如,让我们定义转换函数(函数定义,添加到前面的代码): 这就是问题所在!以前代码中任何定义的不正确!我也不知道该怎么纠正。我在GHCi中得到错误:
2.hs:18:23:
Could not deduce (a ~ a1)
from the context (Show a1, Read a1)
bound by a pattern with constructor
Any :: forall a. (Show a, Read a) => a -> AnyT,
in an equation for `fromAny'
at 2.hs:18:10-18
`a' is a rigid type variable bound by
the type signature for fromAny :: AnyT -> a at 2.hs:17:12
`a1' is a rigid type variable bound by
a pattern with constructor
Any :: forall a. (Show a, Read a) => a -> AnyT,
in an equation for `fromAny'
at 2.hs:18:10
In the expression: thing
In an equation for `fromAny': fromAny (Any thing) = thing
Failed, modules loaded: none.
我也尝试了一些其他的方法来避免犯错误
我有一个非常糟糕的解决方案:通过showAnyT和read来定义必要的函数(替换以前的函数定义): 是的,这是工作。我可以玩它:
*Main> fromAny $ Any 1352 ::Float
1352.0
it :: Float
*Main> fromAny $ Any 1352 ::Int
1352
it :: Int
*Main> fromAny $ Any "Haha" ::String
"Haha"
it :: String
但我认为这很糟糕,因为它使用字符串进行转换
你能帮我找到一个简洁而好的解决办法吗?你有的是一种叫做。如果遵循该链接,您将发现在这种模式中,处理容器类型内“数据”的唯一方法是使用类型类 在您当前的示例中,您提到
a
应该有Read
和Show
实例,这意味着只有这些类型类中的函数可以在a
上使用,其他什么都不能使用,如果您想支持a
上的一些操作,则应该使用所需的类型对其进行约束班级
你可以这样想:你可以把任何东西放在盒子里。现在,当你从那个盒子里取出一些东西时,你无法指定你将从中得到什么,因为你可以把任何东西放进去。现在,如果你说你可以把任何可以吃的东西放在这个盒子里,那么你肯定当你从这个盒子里挑选东西时,它是可以吃的。如果遵循该链接,您将发现在这种模式中,处理容器类型内“数据”的唯一方法是使用类型类 在您当前的示例中,您提到
a
应该有Read
和Show
实例,这意味着只有这些类型类中的函数可以在a
上使用,其他什么都不能使用,如果您想支持a
上的一些操作,则应该使用所需的类型对其进行约束班级
你可以这样想:你可以把任何东西放在盒子里。现在,当你从那个盒子里取出一些东西时,你无法指定你将从中得到什么,因为你可以把任何东西放进去。现在,如果你说你可以把任何可以吃的东西放在这个盒子里,那么你肯定当你从这个盒子里挑选东西时,它是可以吃的。如果遵循该链接,您将发现在这种模式中,处理容器类型内“数据”的唯一方法是使用类型类 在您当前的示例中,您提到
a
应该有Read
和Show
实例,这意味着只有这些类型类中的函数可以在a
上使用,其他什么都不能使用,如果您想支持a
上的一些操作,则应该使用所需的类型对其进行约束班级
你可以这样想:你可以把任何东西放在盒子里。现在,当你从那个盒子里取出一些东西时,你无法指定你将从中得到什么,因为你可以把任何东西放进去。现在,如果你说你可以把任何可以吃的东西放在这个盒子里,那么你肯定当你从这个盒子里挑选东西时,它是可以吃的。如果遵循该链接,您将发现在这种模式中,处理容器类型内“数据”的唯一方法是使用类型类 在您当前的示例中,您提到
a
应该有Read
和Show
实例,这意味着只有这些类型类中的函数可以在a
上使用,其他什么都不能使用,如果您想支持a
上的一些操作,则应该使用所需的类型对其进行约束班级
你可以这样想:你可以把任何东西放在盒子里。现在,当你从那个盒子里取出一些东西时,你无法指定你将从中得到什么,因为你可以把任何东西放进去。现在,如果您说您可以将任何可吃的东西放在这个框中,那么您可以确定,当您从这个框中选择一些东西时,它将是可吃的。您正在使用GADT创建一个存在的数据类型。构造函数中存在类型
a
,但无法恢复。唯一可用的信息是它有Show
和Read
实例。确切的类型被忘记了,因为这是构造函数的类型指示类型系统执行的操作。请确保此类型具有正确的实例,然后忘记它是什么
顺便说一句,你错过了一个功能:
readLike :: String -> AnyT -> AnyT
readLike s (Any a) = Any $ read s `asTypeOf` a
在模式匹配的上下文中,编译器知道无论
a
有什么类型,都有一个Read
实例,它可以应用该实例。即使它不确定a
是什么类型。但是它所能做的就是显示它,或者读取与它相同类型的字符串。您正在使用GADT创建一个存在数据类型。构造函数中存在类型a
,但无法恢复。唯一可用的信息是它有Show
和Read
实例。确切的类型被忘记了,因为这是构造函数的类型指示类型系统执行的操作。请确保此类型具有正确的实例,然后忘记它是什么
顺便说一句,你错过了一个功能:
readLike :: String -> AnyT -> AnyT
readLike s (Any a) = Any $ read s `asTypeOf` a
在模式匹配的上下文中,编译器知道无论a
有什么类型,都有读取
*Main> fromAny $ Any 1352 ::Float
1352.0
it :: Float
*Main> fromAny $ Any 1352 ::Int
1352
it :: Int
*Main> fromAny $ Any "Haha" ::String
"Haha"
it :: String
readLike :: String -> AnyT -> AnyT
readLike s (Any a) = Any $ read s `asTypeOf` a
import Data.Typeable
data AnyT where
Any :: (Show a, Read a, Typeable a) => a -> AnyT
readAnyT :: (Read a, Show a, Typeable a) => (String -> a) -> String -> AnyT
readAnyT readFun str = Any $ readFun str
showAnyT :: AnyT -> String
showAnyT (Any thing) = show thing
toAnyT :: (Show a, Read a, Typeable a) => a -> AnyT -- Rather useless
toAnyT a = Any a
fromAny :: Typeable a => AnyT -> Maybe a
fromAny (Any thing) = cast thing