代码如下。我想让我的函数的参数只受类型类的限制。我在它们上调用类型类的函数然后我可以使用它们。但是当我试图这样做时,我遇到了各种各样的错误。
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, UndecidableInstances #-}
class PlotValue a where
value :: a -> Double
instance PlotValue Double where
value = id
--instance PlotValue Int where
--value x = fromIntegral x
instance (Integral a) => PlotValue a where
value x = fromIntegral x
instance PlotValue String where
value x = 5
type Input = (PlotValue a, PlotValue b) => (Maybe a, Maybe b)
test :: Input -> String
test (Just a, Just b) = (show $ value a) ++ (show $ value b)
main = do
putStrLn (show ( test (Just "strl", Just 6.4)))
当前错误(虽然它们会根据我尝试的内容而略有变化):
Test5.hs:17:5:
Couldn't match expected type `Input' against inferred type `(a, b)'
In the pattern: (Just a, Just b)
In the definition of `test':
test (Just a, Just b) = (show $ value a) ++ (show $ value b)
Test5.hs:20:30:
Couldn't match expected type `a' against inferred type `[Char]'
`a' is a rigid type variable bound by
the polymorphic type
`forall a b. (PlotValue a, PlotValue b) => (Maybe a, Maybe b)'
at Test5.hs:20:19
In the first argument of `Just', namely `"strl"'
In the expression: Just "strl"
In the first argument of `test', namely `(Just "strl", Just 6.4)'
Test5.hs:20:43:
Could not deduce (Fractional b)
from the context (PlotValue a, PlotValue b)
arising from the literal `6.4' at Test5.hs:20:43-45
Possible fix:
add (Fractional b) to the context of
the polymorphic type
`forall a b. (PlotValue a, PlotValue b) => (Maybe a, Maybe b)'
In the first argument of `Just', namely `6.4'
In the expression: Just 6.4
In the first argument of `test', namely `(Just "strl", Just 6.4)'
答案 0 :(得分:2)
修正了许多小事。主要是,正如斯蒂芬所指出的那样,在类型同义词下隐藏自由类型变量通常有点愚蠢和不好。
{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances, OverlappingInstances, UndecidableInstances #-}
class PlotValue a where
value :: a -> Double
instance PlotValue Double where
value = id
instance (Integral a) => PlotValue a where
value x = fromIntegral x
instance PlotValue String where
value x = 5
test :: (PlotValue a, PlotValue b) => (Maybe a, Maybe b) -> String
test (Just a, Just b) = (show $ value a) ++ (show $ value b)
main = do
putStrLn (show ( test (Just "strl", Just (6.4::Double))))
答案 1 :(得分:2)
你真的需要在这里发明新的类型类吗?你会想,Prelude
机器很复杂。只有包含String
可能会迫使你,但还有其他方法。您似乎只想要从标准数字类型(Int
,Integer
,Float
,Double
)到Double
的一般映射。有很多方法可以解决这个问题,但是d
在这里取代value
呢?
d :: Real a => a -> Double
d = fromRational . toRational
test (Just a, Just b) = show (d a) ++ " " ++ show (d b)
test (_, _)= "Something's missing"
-- Main> :t test
-- test :: (Real a, Real a1) => (Maybe a, Maybe a1) -> [Char]
double :: Double
double = 1.0
float :: Float
float = 1.0
int :: Int
int = 1
integer :: Integer
integer = 2
omnibus = d double * d float * d int / d integer
jdouble = Just double
jinteger = Just integer
goodtest = (jdouble,jinteger)
badtest = (Nothing, jinteger)
main = print omnibus >> putStrLn (test goodtest) >> putStrLn (test badtest)
-- Main> main
-- 0.5
-- 1.0 2.0
-- Something's missing
如果您希望将d
应用于String
,则需要使用数字处理字符串。好的,一种方法是为Num
定义String
实例,以便创建Real
实例。只需谷歌“实例Num字符串”,或参见例如例如this remark of dons
。这是一个无聊的例子:
instance Num String where
fromInteger = show
(+) = (++)
x * y = concatMap (const y) x
abs = undefined
signum = undefined
instance Real String where toRational = toRational . d . length
-- Main> fromInteger 500 * "moo "
-- "moo moo moo "
-- Main> d (fromInteger 500 * "moo")
-- 12.0
stringy = d "string"
jstringy = Just stringy
stringytest = (jstringy, jinteger)
main' = print omnibus >> print stringy >>
putStrLn (test goodtest) >> putStrLn (test badtest) >>
putStrLn (test stringytest)
-- Main> main'
-- 0.5
-- 5.0
-- 1.0 2.0
-- Something's missing
-- 5.0 2.0
或者,如果您想要一个PlotValue
类型的value
类,为什么不分别为四种主要数字类型和String
实例化?事实上,您似乎想要的Input
类型实际上类似于(Maybe Double, Maybe Double)
。
请注意你写的地方
main = do
putStrLn (show ( test (Just "strl", Just 6.4)))
您不需要do
,因为您只需查看一个操作;并且您不需要“显示”,因为test
已经产生String
。
答案 2 :(得分:1)
为了绕过(对我来说)'奇怪'类型的同义词,我会选择GADT,就像这样:
{-# LANGUAGE GADTs #-} -- in addition to the rest
data Input where
Input :: (PlotValue a, PlotValue b) => Maybe a -> Maybe b -> Input
test :: Input -> String
test (Input (Just a) (Just b)) = (show $ value a) ++ (show $ value b)
唯一的开销是必须匹配Input
构造函数。
(有关课程和实例设计的问题已经得到解答,所以我不会进入这些问题)