类型类函数的显式forall

leh*_*ins 11 haskell typeclass forall

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

?> show (5 :: Int)
"5"
Run Code Online (Sandbox Code Playgroud)

这样做是这样的:

?> :set -XTypeApplications
?> show @Int 5
"5"
Run Code Online (Sandbox Code Playgroud)

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

showFooBar :: (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
Run Code Online (Sandbox Code Playgroud)

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

?> showFooBar @Int @Double 3 4
"3 and 4.0"
Run Code Online (Sandbox Code Playgroud)

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

{-# LANGUAGE ExplicitForAll #-}

showFooBar :: forall b a . (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
Run Code Online (Sandbox Code Playgroud)

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

?> showFooBar @Int @Double 3 4
"3.0 and 4"
Run Code Online (Sandbox Code Playgroud)

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

{-# LANGUAGE MultiParamTypeClasses #-}

class (Show a, Show b) => FooBar a b where
  fooBarClassFunc :: a -> b -> String
Run Code Online (Sandbox Code Playgroud)

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

那么,问题是,为了TypeApplication类型类方法的内部,你如何改变类型变量的顺序?

编辑

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

Ant*_*ntC 2

如何更改类型变量的顺序以达到TypeApplication类型类方法内部的目的?

我认为@luqui 的答案已经足够好了。但为什么不是这个:

class (Show b, Show a) => FooBar b a where
  fooBarClassFunc :: a -> b -> String
Run Code Online (Sandbox Code Playgroud)

您只有一种方法,因此驱动类参数顺序的唯一考虑因素是TypeApplication方法内部的目的。

如果您有两个或多个方法,您希望其顺序TypeApplication不同(@chi 的观点,但为什么?),那么对于其他方法,要么 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
Run Code Online (Sandbox Code Playgroud)

(假设otherFooBarClassFunc'在主类中定义;这就是真正的实例定义所在的地方。)

对于每个类的一个方法有很多话要说当然,

{-# NOOVERLAPPABLE #-}我们不知道什么是我的小笑话。