简体   繁体   English

类型类函数的显式forall

[英]Explicit forall on a type class function

Since ghc-8.0 we have a very nice extension called TypeApplications . 从ghc-8.0开始,我们有一个非常好的扩展名为TypeApplications Which allows us instead of: 这允许我们而不是:

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

do so something like that: 这样做是这样的:

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

Which is really cool. 这真的很酷。 It becomes a bit more involved when we add more type variables, but there are rules that can be used to determine the exact order, and they are very well documented: 当我们添加更多类型变量时,它会变得更加复杂,但是有一些规则可以用来确定确切的顺序,并且它们有很好的记录:

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

So in the function above we would first supply a and then b : 所以在上面的函数中我们首先提供a然后b

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

That's great, but what if I'd like to change the order? 这很好,但是如果我想改变订单怎么办? No problem there, we can use ExplicitForAll extension (or some other that imply it) to specify it: 没问题,我们可以使用ExplicitForAll扩展(或其他一些暗示它)来指定它:

{-# LANGUAGE ExplicitForAll #-}

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

And now we reversed the order of types that we are going to apply: 现在我们颠倒了我们要应用的类型顺序:

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

The problem is that I can't seem to figure out how to achieve the same affect for functions that are part of a type class. 问题是我似乎无法弄清楚如何为属于类型类的函数实现相同的效果。 Consider this example: 考虑这个例子:

{-# LANGUAGE MultiParamTypeClasses #-}

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

I can't put forall on a function now (eg. fooBarClassFunc :: forall ab . a -> b -> .. , cause that changes the meaning of the function and obviously does not compile. 我现在不能把forall放在一个函数上(例如fooBarClassFunc :: forall ab . a -> b -> .. ,因为它改变了函数的含义,显然不能编译。

So, the question is, how do you change the order of type variables for the purpose of TypeApplication inside the type class methods? 那么,问题是,在类型类方法中,如何为TypeApplication更改类型变量的顺序?

Edit 编辑

Just in case, I have tried InstanceSigs extension, and it completely ignores the order of forall type variables as far as TypeApplications are concerned, which is a good thing, otherwise we would end up with behavior that is determined by the instance, rather than the class. 为了以防万一,我已经尝试过InstanceSigs扩展,并且就TypeApplications而言它完全忽略了forall类型变量的顺序,这是一件好事,否则我们最终会得到由实例决定的行为,而不是类。

how do you change the order of type variables for the purpose of TypeApplication inside the type class methods? 在类型类方法中,如何为TypeApplication更改类型变量的顺序?

@luqui's answer is good enough, I would think. 我想,@ luqui的答案已经足够好了。 But why not this: 但为什么不这样:

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

You only have one method, so the only consideration driving the order of parameters to the class is for the purpose of TypeApplication inside the methods. 您只有一个方法,因此驱动类的参数顺序的唯一考虑因素是方法中的TypeApplication

If you have two or more methods for which you want the order of TypeApplication to be different (@chi's point, but why?), then for the other methods either luqui's suggestion, or (equivalently) an other class with a superclass constraint and a default implementation. 如果有两个或更多的方法您想要的顺序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

(Assuming otherFooBarClassFunc' is defined in the main class; and that's where the real instance definition goes on.) (假设在主类中定义了otherFooBarClassFunc' ;那就是真实实例定义所在的位置。)

There is a lot to be said for one method per class , of course. 当然, 每个班级有一个方法可以说很多。

{-# NOOVERLAPPABLE #-} wot we do not 'ave is my little in-joke. {-# NOOVERLAPPABLE #-}我们不是'ave'是我的小玩笑。

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

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