Ash*_*ary 4 haskell scala typeclass
我该如何说可以为那些属于 的实例但不提及其他s的实例B创建:mAm
-- A.hs
module A where
class A m -- m :: * -> *
-- B.hs, totally unrelated to A
module B where
class B m
-- Utilities.hs
module Utilities where
given A m then instance B m -- like given in Scala 3
Run Code Online (Sandbox Code Playgroud)
请注意我不想说:
class A => class B -- B requires A
Run Code Online (Sandbox Code Playgroud)
他们B不知道也不应该知道A。与class级别B无关A。B仅根据其最小完整定义进行定义,该定义在其where子句(此处未显示)之后表达,并且不了解A或任何其他类别。其实B是独立的。
我也不想说:
instance A m => B m -- *all* m are B, this requires A m as well
-- actually this errors out with a "constraint is no smaller than head"
-- which is fixed by `newtype`ing around the `m` in `B`
-- but this is besides the point
Run Code Online (Sandbox Code Playgroud)
这说所有 ms 都是Bs,并且还要求所有m也是As,这是不正确的,也不是我想说的。这不是 Scala 行(blow)所说的。
我想说的正是这样的:有一个B,它定义了某个接口。还有一个完全不相关的A。B没有根据其定义,也没有在其定义A站点以任何方式要求。现在,其他人出现了,并且知道了一种方法来创建for的实例(如果存在for 的实例)。ABmA
在 Scala 中我可以轻松地说:
implicit def fromA[M: A]: B[M] = ...
Run Code Online (Sandbox Code Playgroud)
这就是说,如果您可以证明M是 an A(在 Scala 中,这是通过将 animplicit A[M]引入范围来实现的),那么我可以自动构造 的B实例M。特别是,这不会B对所有s 施加强制,并且如果对于某些 s 不成立M也不是错误。您可以自由地自行构建。上面的(第二个)Haskell 代码并不等同于这个 Scala 代码。A[M]MBM
我正在寻找 Haskell 中的等效项
更新显然在 Haskell 中没有办法做到这一点
更新2这是这个问题背后的具体案例无法以无标记最终方式/使用类型类和实例对我的组件进行编码
你想要的却做不到* ; 所有已经拥有实例的事物A也必须显式地列为B实例。但您可以最小化样板文件。
如果您控制 的定义B,则可以使用DefaultSignatures:
class A m where foo :: m -> m -> m
instance A Int where foo = {- ... -}
instance A Bool where foo = {- ... -}
instance A Char where foo = {- ... -}
class B m where
bar :: m -> m -> m -> m
default bar :: A m => m -> m -> m -> m
bar m0 m1 m2 = foo (foo m0 m1) m2
-- N.B. no instance body needed
instance B Int
instance B Bool
instance B Char
Run Code Online (Sandbox Code Playgroud)
如果您不控制 的定义B,则可以创建一个包装器 newtype 并使用,如果您也不控制已经是 的实例的类型的定义,则DerivingVia可能会扔进去。StandaloneDerivingA
class A m where foo :: m -> m -> m
instance A Int where foo = {- ... -}
instance A Bool where foo = {- ... -}
instance A Char where foo = {- ... -}
class B m where
bar :: m -> m -> m -> m
newtype BViaA m = BViaA m
instance A m => B (BViaA m) where
bar (BViaA m0) (BViaA m1) (BViaA m2) = BViaA (foo (foo m0 m1) m2)
-- still no body
deriving instance B Int via (BViaA Int )
deriving instance B Bool via (BViaA Bool)
deriving instance B Char via (BViaA Char)
Run Code Online (Sandbox Code Playgroud)
也可以看看:
*好的。你想要的事情不可能理智地完成。我相信你可以使用一些扭曲IncoherentInstances,但它们很脆弱,我强烈建议不要使用它们。