我想创建一个具有类型约束的函数定义的实例,但我不想将类型约束添加到类中.
class Foo a where
f :: a b -> b
instance Foo Maybe where
f = fMaybe
fMaybe :: (Num a) => Maybe a -> a
fMaybe (Just i) = i+i
fMaybe _ = 0
Run Code Online (Sandbox Code Playgroud)
如何指定这是Maybe包含s 的实例Nums?
这有效:
{-# LANGUAGE MultiParamTypeClasses #-}
class Foo a b where
f :: a b -> b
instance Foo Maybe Int where
f = fMaybe
fMaybe :: (Num a) => Maybe a -> a
fMaybe (Just i) = i+i
fMaybe _ = 0
Run Code Online (Sandbox Code Playgroud)
但我不想为每种类型声明实例 Num
我试过这个:
class Foo a where
f :: a -> b
instance (Num b) => Foo (Maybe b) where
f = fMaybe
fMaybe :: (Num a) => Maybe a -> a
fMaybe (Just i) = i+i
fMaybe _ = 0
Run Code Online (Sandbox Code Playgroud)
但是我收到一个错误:
Run Code Online (Sandbox Code Playgroud)Couldn't match type ‘b’ with ‘b1’ ‘b’ is a rigid type variable bound by the instance declaration at Test.hs:31:10 ‘b1’ is a rigid type variable bound by the type signature for f :: Maybe b -> b1 at Test.hs:32:3 Expected type: Maybe b -> b1 Actual type: Maybe b1 -> b1 Relevant bindings include f :: Maybe b -> b1 (bound at Test.hs:32:3) In the expression: fMaybe In an equation for ‘f’: f = fMaybe
不改变类或类型是不可能的.
该MultiParamTypeClasses方法实际上并不要求您为所有Num类型编写单独的实例- 以下工作:
class Foo a b where
f :: a b -> b
instance (Num b) => Foo Maybe b where
f = fMaybe
Run Code Online (Sandbox Code Playgroud)
不过,我认为这不是一个特别好的方法.
您可以使用ConstraintKinds允许每个实例有选择地约束包含的类型.
{-# LANGAUGE TypeFamilies, ConstraintKinds #-}
import GHC.Exts (Constraint)
class Foo a where
type FooCstrt a b :: Constraint
type FooCstrt a b = () -- default to unconstrained
f :: FooCstrt a b => a b -> b
instance Foo Maybe where
type FooCstrt Maybe b = Num b
f = fMaybe
Run Code Online (Sandbox Code Playgroud)您可以切换到仅允许首先包含Num类型的类型.
{-# LANGUAGE GADTs #-}
data NMaybe where
NJust :: Num b => b -> NMaybe b
NNothing :: Num b => NMaybe b
Run Code Online (Sandbox Code Playgroud)
然后,
class Foo a where
f :: a b -> b
instance Foo NMaybe where
f (NJust i) = i+1
f (NNothing) = 0
Run Code Online (Sandbox Code Playgroud)