在实例声明中键入约束但不在类中键入

bwr*_*oga 1 haskell

我想创建一个具有类型约束的函数定义的实例,但我不想将类型约束添加到类中.

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)

但是我收到一个错误:

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
Run Code Online (Sandbox Code Playgroud)

lef*_*out 6

不改变类或类型是不可能的.

  • 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)