如何接受仅受类型类限制的参数

时间:2011-03-24 12:00:07

标签: haskell typeclass

代码如下。我想让我的函数的参数只受类型类的限制。我在它们上调用类型类的函数然后我可以使用它们。但是当我试图这样做时,我遇到了各种各样的错误。

{-# 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)'

3 个答案:

答案 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可能会迫使你,但还有其他方法。您似乎只想要从标准数字类型(IntIntegerFloatDouble)到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构造函数。

(有关课程和实例设计的问题已经得到解答,所以我不会进入这些问题)