如何根据上下文制作 class 的不同实例?
How to make the different instances of class, depending on context?
我有一些简单的 class 和一些用于各种数据类型和上下文的实例。这是一个部分工作的案例:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}
class Neighbors a where
(~~) :: a -> a -> Bool
instance Neighbors Int where
x ~~ y = (abs (x-y) == 1)
instance (RealFloat a) => Neighbors a where
x ~~ y = (abs(x-y) < 1.0)
缺点是我必须对 Int
:
使用类型限制
*Main> (1::Int) ~~ (2::Int)
True
但是,如果我只想使用上下文,我的第二个脚本根本不起作用:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}
class Neighbors a where
(~~) :: a -> a -> Bool
instance (Integral a) => Neighbors a where
x ~~ y = (abs(x-y) == 1)
instance (RealFloat a) => Neighbors a where
x ~~ y = (abs(x-y) < 1.0)
错误是:
Neighborhood.hs:7:10: error:
Duplicate instance declarations:
instance [incoherent] Integral a => Neighbors a
-- Defined at Neighborhood.hs:7:10
instance [incoherent] RealFloat a => Neighbors a
-- Defined at Neighborhood.hs:10:10
Failed, modules loaded: none.
但我想为这些不同的上下文定义不同的实例:Integral 和 RealFloat。如何在一个文件中完成?
您可以像这样在一个文件中完成:
instance Neighbors Int where x ~~ y = abs (x-y) == 1
instance Neighbors Double where x ~~ y = abs (x-y) < 1
instance Neighbors Float where x ~~ y = abs (x-y) < 1
instance Neighbors CDouble where x ~~ y = abs (x-y) < 1
instance Neighbors CFloat where x ~~ y = abs (x-y) < 1
instance RealFloat a => Neighbors (Identity a) where x ~~ y = abs (x-y) < 1
instance RealFloat a => Neighbors (Const a b) where x ~~ y = abs (x-y) < 1
我知道您不喜欢为每个类型构造函数编写一个实例;但这是对所问问题的正确答案,因为类型构造函数是 Haskell 类型类进行分派的方式。
您可以通过定义
来减少一些重复
neighborsDef :: (Num a, Ord a) => a -> a -> Bool
neighborsDef x y = abs (x-y) < 1
并在实例中给出 (~~) = neighborsDef
。
事实上,我怀疑你根本不想要一个新的类型类。也许以下两个定义之一适合您:
(~~) :: (Num a, Ord a) => a -> a -> Bool
x ~~ y = abs (x-y) <= 1 -- if the Int definition was slightly off, OR
x ~~ y = x /= y && abs (x-y) <= 1 -- if the RealFloat definition was slightly off
我有一些简单的 class 和一些用于各种数据类型和上下文的实例。这是一个部分工作的案例:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}
class Neighbors a where
(~~) :: a -> a -> Bool
instance Neighbors Int where
x ~~ y = (abs (x-y) == 1)
instance (RealFloat a) => Neighbors a where
x ~~ y = (abs(x-y) < 1.0)
缺点是我必须对 Int
:
*Main> (1::Int) ~~ (2::Int)
True
但是,如果我只想使用上下文,我的第二个脚本根本不起作用:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, IncoherentInstances #-}
class Neighbors a where
(~~) :: a -> a -> Bool
instance (Integral a) => Neighbors a where
x ~~ y = (abs(x-y) == 1)
instance (RealFloat a) => Neighbors a where
x ~~ y = (abs(x-y) < 1.0)
错误是:
Neighborhood.hs:7:10: error:
Duplicate instance declarations:
instance [incoherent] Integral a => Neighbors a
-- Defined at Neighborhood.hs:7:10
instance [incoherent] RealFloat a => Neighbors a
-- Defined at Neighborhood.hs:10:10
Failed, modules loaded: none.
但我想为这些不同的上下文定义不同的实例:Integral 和 RealFloat。如何在一个文件中完成?
您可以像这样在一个文件中完成:
instance Neighbors Int where x ~~ y = abs (x-y) == 1
instance Neighbors Double where x ~~ y = abs (x-y) < 1
instance Neighbors Float where x ~~ y = abs (x-y) < 1
instance Neighbors CDouble where x ~~ y = abs (x-y) < 1
instance Neighbors CFloat where x ~~ y = abs (x-y) < 1
instance RealFloat a => Neighbors (Identity a) where x ~~ y = abs (x-y) < 1
instance RealFloat a => Neighbors (Const a b) where x ~~ y = abs (x-y) < 1
我知道您不喜欢为每个类型构造函数编写一个实例;但这是对所问问题的正确答案,因为类型构造函数是 Haskell 类型类进行分派的方式。
您可以通过定义
来减少一些重复neighborsDef :: (Num a, Ord a) => a -> a -> Bool
neighborsDef x y = abs (x-y) < 1
并在实例中给出 (~~) = neighborsDef
。
事实上,我怀疑你根本不想要一个新的类型类。也许以下两个定义之一适合您:
(~~) :: (Num a, Ord a) => a -> a -> Bool
x ~~ y = abs (x-y) <= 1 -- if the Int definition was slightly off, OR
x ~~ y = x /= y && abs (x-y) <= 1 -- if the RealFloat definition was slightly off