繁体   English   中英

类型类函数的显式forall

[英]Explicit forall on a type class function

从ghc-8.0开始,我们有一个非常好的扩展名为TypeApplications 这允许我们而不是:

λ> show (5 :: Int)
"5"

这样做是这样的:

λ> :set -XTypeApplications
λ> show @Int 5
"5"

这真的很酷。 当我们添加更多类型变量时,它会变得更加复杂,但是有一些规则可以用来确定确切的顺序,并且它们有很好的记录:

showFooBar :: (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b

所以在上面的函数中我们首先提供a然后b

λ> showFooBar @Int @Double 3 4
"3 and 4.0"

这很好,但是如果我想改变订单怎么办? 没问题,我们可以使用ExplicitForAll扩展(或其他一些暗示它)来指定它:

{-# LANGUAGE ExplicitForAll #-}

showFooBar :: forall b a . (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b

现在我们颠倒了我们要应用的类型顺序:

λ> showFooBar @Int @Double 3 4
"3.0 and 4"

问题是我似乎无法弄清楚如何为属于类型类的函数实现相同的效果。 考虑这个例子:

{-# LANGUAGE MultiParamTypeClasses #-}

class (Show a, Show b) => FooBar a b where
  fooBarClassFunc :: a -> b -> String

我现在不能把forall放在一个函数上(例如fooBarClassFunc :: forall ab . a -> b -> .. ,因为它改变了函数的含义,显然不能编译。

那么,问题是,在类型类方法中,如何为TypeApplication更改类型变量的顺序?

编辑

为了以防万一,我已经尝试过InstanceSigs扩展,并且就TypeApplications而言它完全忽略了forall类型变量的顺序,这是一件好事,否则我们最终会得到由实例决定的行为,而不是类。

在类型类方法中,如何为TypeApplication更改类型变量的顺序?

我想,@ luqui的答案已经足够好了。 但为什么不这样:

class (Show b, Show a) => FooBar b a where
  fooBarClassFunc :: a -> b -> String

您只有一个方法,因此驱动类的参数顺序的唯一考虑因素是方法中的TypeApplication

如果有两个或更多的方法您想要的顺序TypeApplication是不同的(@志的观点,但为什么呢?),然后换另一方法或者luqui的建议,或(等效)的其他类与父约束和默认实现。

class (Show a, Show b, FooBar b a) => OtherFooBar a b where
  otherFooBarClassFunc :: a -> b -> String
  otherFooBarClassFunc = otherFooBarClassFunc'  -- default
instance {-# NOOVERLAPPABLE #-} OtherFooBar a b  where {}  -- take default

(假设在主类中定义了otherFooBarClassFunc' ;那就是真实实例定义所在的位置。)

当然, 每个班级有一个方法可以说很多。

{-# NOOVERLAPPABLE #-}我们不是'ave'是我的小玩笑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM