我如何获得特定类型类实例的多态函数的类型? [英] How can i get the type of a polymorphic function for a specific type class instance?

查看:136
本文介绍了我如何获得特定类型类实例的多态函数的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,在GHCi中输入:t ap 可得到结果

  ap :: Monad m => m(a  - > b) - > m a  - > mb 

如果我已经知道Monad实例,我将使用 (( - >)r),我该如何查询该特定实例的 ap 类型?

解决方案

您可以使用可见类型应用程序功能来指定参数类型。您可以更有创意地查看函数: Haskell 中的函数不仅可以应用于某些类型的值,还可以应用于该类型的值。但是为了传递类型,你应该以某种方式指定(带有 @ )来传递类型(因为类型不是 Haskell中的头等对象

所以在这里它是如何工作的:

 λ: :set -XTypeApplications 
λ::t ap @(( - >)Int)
ap @(( - >)Int)::(Int - > a - > b) - > (Int→a)→> Int - > b

这种方法的唯一限制是您不能在<$ c $中使用类型变量c> ghci ,你应该使用特定的类型( Int 而不是 r ),但是这个是不是什么大问题。



高级部分

但它很棘手:

 λ::set -XExplicitForAll 
λ::set -XPartialTypeSignatures
λ: :set -XScopedTypeVariables
λ::{
λ| foo :: forall r。 _
λ| foo = ap @(( - >)r)
λ| :}
< interactive>:28:19:warning:[-Wpartial-type-signature]
•找到类型通配符'_'
代表'(r - > a - > b) - > (r→a)→> r - > b'
λ::t foo
foo ::(r - > a - > b) - > (r→a)→> r - > b

UPD:实际上可以使用占位符而不是类型变量(请参阅另一个答案)。但是如果你想用上面的方法指定确切的名字。

 λ::t ap @(( - >)_ )
ap @(( - >)_)::(t - > a - > b) - > (t→a)→> t - > b

/ ADVANCED SECTION



关于这种方法还有一件事要说:如果你的函数有几个类型参数,并且你想指定一个确切的参数,你应该做更多的事情。类型从左到右依次传递,就像 bar :: Int - >等一些函数中的简单参数一样。字符串 - >双。如果你想修改 bar 的第一个参数,你应该写 bar 5 ,如果你想修正第二个参数,好吧,你可以写一些像 \\\
- > bar nbaz
但这不适用于类型应用程序。您需要知道两件事:



  1. 类型顺序。

  2. 如何指定所需的类型。

考虑下一个功能:

 λ::t lift 
lift ::(Monad m,MonadTrans t)=> m a - > tma

我们希望能够指定 m t 类型变量。由于 Haskell 没有命名类型变量(尚),所以不能写:t lift {t = MaybeT} 或者:不幸的是,提升{m = IO} 。所以回到两件事。



要查看类型的顺序,您应该使用一些编译器选项。类型参数的顺序由 forall 指定,您可以手动执行。否则,编译器会以某种方式对类型参数进行排序。单纯的凡人看不到 lift 函数的类型顺序,但是如果你意识到某些高级魔法,你可以:

 λ::set -fprint-explicit-foralls 
λ::t lift
lift
:: forall {t ::( * - > *) - > * - > *} {a} {m :: * - > *}。
(Monad m,MonadTrans t)=>
m a - > tma

然后您应该使用 @_ 跳过一些类型:

 λ::t lift @MaybeT 
lift @MaybeT
:: forall {a} {m :: * - > *}。 Monad m => m a - > MaybeT m a
λ::t lift @_ @IO
lift @_ @IO
:: forall {t ::(* - > *) - > * - > *} {一个}。
MonadTrans t =>
IO a - > t IO a
λ::t lift @_ @ @Int
lift @_ @ @ @nt
:: forall {t ::(* - > *) - > * - > *} {t1 :: * - > *}。
(Monad t1,MonadTrans t)=>
t1 Int - >那么,这对我来说真的很神秘,为什么 m

code>在 forall 中显示为 third 参数,但应该作为 second传递,但我仍然不知道所有的魔法。


For example, typing :t ap in GHCi gives the result

ap :: Monad m => m (a -> b) -> m a -> m b

If I already know the Monad instance I'm going to use is ((->) r), how can I query for the type of ap for that specific instance?

解决方案

You can use visible type application feature to specify parametric types. You can look at functions in more creative way: functions in Haskell can be applied to not only values of some types, but also to types of that values. But to pass type you should somehow specify (with prepending @) that you're passing types (because types are not first-class objects in Haskell yet).

So here how it works:

λ: :set -XTypeApplications
λ: :t ap @((->) Int)
ap @((->) Int) :: (Int -> a -> b) -> (Int -> a) -> Int -> b

The only limitation of such approach is that you can't use type variables in ghci, you should use specific types (Int instead of r) but this is not big deal.

ADVANCED SECTION

Well, actually you can, but it's tricky:

λ: :set -XExplicitForAll 
λ: :set -XPartialTypeSignatures 
λ: :set -XScopedTypeVariables 
λ: :{
λ| foo :: forall r . _
λ| foo = ap @((->) r)
λ| :}
<interactive>:28:19: warning: [-Wpartial-type-signatures]
    • Found type wildcard ‘_’
        standing for ‘(r -> a -> b) -> (r -> a) -> r -> b’
λ: :t foo
foo :: (r -> a -> b) -> (r -> a) -> r -> b

UPD: You can actually use placeholders instead of type variables (see another answer). But if you want to specify exact names use approach from above.

λ: :t ap @((->) _)
ap @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b

/ADVANCED SECTION

One more thing to say about this approach: you should do something more if your functions have several type parameters and you want to specify exact one. Types are passed one by one from left to right just as simple arguments in some function like bar :: Int -> String -> Double. If you want to fix first argument of bar you should write bar 5 and if you want to fix second, then, well, you can write something like \n -> bar n "baz" but this doesn't work with type application. You need to know two things:

  1. Order of types.
  2. How to specify desired type.

Consider next function:

λ: :t lift
lift :: (Monad m, MonadTrans t) => m a -> t m a

We want be able to specify m and t type variables. Because Haskell has no named type variables (yet) you can't write :t lift {t=MaybeT} or :t lift {m=IO} unfortunately. So go back to two things.

To see order of types you should use some compiler options. Order of type arguments is specified by forall and you can do it manually. Otherwise type parameters will be sorted somehow by the compiler. Mere mortals can't see order of types for lift function but if you're aware of some high-level magic you can:

λ: :set -fprint-explicit-foralls
λ: :t lift
lift
  :: forall {t :: (* -> *) -> * -> *} {a} {m :: * -> *}.
     (Monad m, MonadTrans t) =>
     m a -> t m a

And then you should use @_ to skip some types:

λ: :t lift @MaybeT
lift @MaybeT
  :: forall {a} {m :: * -> *}. Monad m => m a -> MaybeT m a
λ: :t lift @_ @IO
lift @_ @IO
  :: forall {t :: (* -> *) -> * -> *} {a}.
     MonadTrans t =>
     IO a -> t IO a
λ: :t lift @_ @_ @Int
lift @_ @_ @Int
  :: forall {t :: (* -> *) -> * -> *} {t1 :: * -> *}.
     (Monad t1, MonadTrans t) =>
     t1 Int -> t t1 Int

Well, this is really mystery for me why m is shown as third argument in forall but should be passed as second but I'm still not aware of all magic.

这篇关于我如何获得特定类型类实例的多态函数的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆