如何仅为Floating创建实例?

Ite*_*tor 2 haskell

有一个类,我想为其定义一个实例.它看起来像这样:

data MyValue a = MyValue a

class TestClass a where
    funcOne:: (Real b) => a b -> a b
    funcTwo:: (Real b) => a b -> a b -> a b


instance TestClass MyValue where
    funcOne (MyValue x) = MyValue (x*pi)
    funcTwo (MyValue x) (MyValue y) = MyValue (x*y)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Could not deduce (Floating b) arising from a use of `pi'
      from the context: Real b
Run Code Online (Sandbox Code Playgroud)

我理解错误,但我不知道如何解决它.

我无法更改(Real b)to,(Floating b)因为其他实例也应该使用Integral类型.但仅有MyValue意义Floating.有可能告诉编译器,instance TestClass MyValue只能使用Floating

如果不是,那么如何将结果转换x*piRealx参数相同的?如果类型是例如Integral,会发生什么并不重要,因为MyValue在这种情况下没有意义

lef*_*out 6

您可以实现此目的,但您需要修改该数据类型或类.

  • 如果MyValue使用Floating特别有意义,那么将该约束烘焙到其构造函数中可能是有意义的.

    {-# LANGUAGE GADTs #-}
    
    data MyValue :: * -> * where
      MyValue :: Floating a => a -> MyValue a
    
    Run Code Online (Sandbox Code Playgroud)

    这保证任何功能接受MyValue aa实际上是一个Floating实例,因此

      funcOne (MyValue x) = MyValue $ x*pi
    
    Run Code Online (Sandbox Code Playgroud)

    然后会工作.

  • 如果这是一个共同的主题,需要对包含的类型进行特定约束,那么您可以(而不是总是要求Real)使约束依赖于实例:

    {-# LANGUAGE TypeFamilies, ConstraintKinds #-}
    import GHC.Exts (Constraint)
    
    class TestClass a where
      type Testable a b :: Constraint
      type Testable a b = Real b  -- default constraint
      funcOne:: Testable b => a b -> a b
      funcTwo:: Testable b => a b -> a b -> a b
    
    instance TestClass MyValue where
      type Testable MyValue b = Floating b
      funcOne (MyValue x) = MyValue $ x*pi
      ...
    
    Run Code Online (Sandbox Code Playgroud)
  • 但是,如果您需要再次人为地约束参数,那么首先TestClass处理参数化(* -> *)类型可能不是正确的决定.为什么不简单地做

    class TestClass q where
      funcOne :: q -> q
      funcTwo :: q -> q -> q
    
    instance Floating a => TestClass (MyValue a) where
      funcOne (MyValue x) = MyValue $ x*pi
      funcTwo (MyValue x) (MyValue y) = MyValue $ x*y
    
    Run Code Online (Sandbox Code Playgroud)

    无论如何,这对我来说似乎更干净.如果某些方法确实需要访问包含的类型,那么使用相关类型系列也可以使用此方法:

    class TestClass q where
      type ToTest q :: *
      ...
    
    instance Floating a => TestClass (MyValue a) where
      type ToTest (MyValue a) = a
      ...
    
    Run Code Online (Sandbox Code Playgroud)