haskell ghci能告诉我们一个类的哪个示例正在被使用吗

xv8emn3q  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(84)

这是些ghci

> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
> :t allEqual
allEqual :: Eq a => [a] -> [a] -> Bool
> :t allEqual <*> reverse
allEqual <*> reverse :: Eq a => [a] -> Bool
> :t reverse
reverse :: [a] -> [a]

字符串
我试图弄清楚allEqual <*> reverse中应用程序的示例到底是什么。
我试着解释

f (a -> b) :: [a] -> [a] -> Bool
f a :: [a] -> [a]
f b :: [a] -> Bool


但这没有意义,因为f ba相关。
他们是想让ghci告诉我这里实际上使用了什么应用程序f。如果不是,haskellers是如何推理这些东西的。

8wtpewkr

8wtpewkr1#

你可以使用-ddump-ds让GHC显示它正在使用的示例,如下所示:

GHCi, version 9.8.1: https://www.haskell.org/ghc/  :? for help
ghci> :{
ghci| allEqual :: Eq a => [a] -> [a] -> Bool
ghci| allEqual = undefined -- or your actual definition
ghci| :}
ghci> :set -ddump-ds -dsuppress-all -dno-suppress-type-applications
ghci> x = allEqual <*> reverse

==================== Desugared ====================
letrec {
  x_aR1
    = \ @a_aSP $dEq_aT1 ->
        let { $dEq_aSQ = $dEq_aT1 } in
        let { $dApplicative_aSL = $fApplicativeFUN @[a_aSP] } in
        letrec {
          x_aSW
            = <*>
                @((->) [a_aSP])
                $dApplicative_aSL
                @[a_aSP]
                @Bool
                (allEqual @a_aSP $dEq_aSQ)
                (reverse @a_aSP); } in
        x_aSW; } in
returnIO
  @[Any]
  (: @Any
     (unsafeCoerce#
        @LiftedRep
        @LiftedRep
        @(forall {a}. Eq a => [a] -> Bool)
        @Any
        x_aR1)
     ([] @Any))

ghci>

字符串
输出中<*>后面的@((->) [a_aSP])表示它正在使用函数示例(在文档中列为Applicative ((->) r)示例)。
或者,您可以在没有GHC帮助的情况下,仅通过查看类型来解决问题,如下所示:

(<*>) :: Applicative f => f (a -> b) -> f a -> f b
allEqual :: Eq a => [a] -> [a] -> Bool
reverse :: [a] -> [a]


为了简单起见,我将对后两种类型进行alpha转换,以不重用a类型变量:

allEqual :: Eq t => [t] -> [t] -> Bool
reverse :: [t] -> [t]


记住->是右相联的,也可以写成前缀形式,所以[t] -> [t] -> Bool(->) [t] ([t] -> Bool)一样。由于allEqual<*>的第一个参数,所以它的类型必须和f (a -> b)统一。同样,作为第二个参数,reverse的类型必须和f a统一,当你把所有的都插进去的时候,你会得到f必须是(->) [t]a必须是[t],并且b必须是Bool。快速检查这是否正确是观察f b然后是[t] -> Bool,在alpha等价之后是与allEqual <*> reverse的输出相同的类型GHC推断。由于fApplicative示例所需要的,它必须使用(->) [t]的示例(以列表为参数的函数)。执行:instances ((->) [t])将显示instance Applicative ((->) [t]) -- Defined in ‘GHC.Base’,但实际使用的示例更通用,任何类型的函数都可以使用。一旦找到函数箭头,执行:info (->)将显示:instance Applicative ((->) r) -- Defined in ‘GHC.Base’

wko9yo5t

wko9yo5t2#

我有时使用的一个快速技巧是添加一个类型化的孔,如(polymorphicValueasTypeOf_)
更准确地说,asTypeOf是一个定义为

asTypeOf :: t -> t -> t
asTypeOf x y = x

字符串
它与const非常相似,但它 * 强制 * 它的两个参数xy具有相同的类型。
在表达式的中间添加一个类型化的洞_,告诉GHC引发一个类型错误,告诉应该使用什么类型来填充这个洞。
因此,(thingasTypeOf_)要求GHC打印thing的类型,这在thing是多态的时候非常有用。
让我们把这个应用到你的案例中:

ghci> :t allEqual <*> reverse
allEqual <*> reverse :: Eq a => [a] -> Bool


首先,我们将(<*>)移动到前缀表示法。

ghci> :t (<*>) allEqual reverse
(<*>) allEqual reverse :: Eq a => [a] -> Bool


然后,我们插入键入的孔:

ghci> :t ((<*>) `asTypeOf` _) allEqual reverse
    * Found hole:
        _ :: ([a] -> [a] -> Bool) -> ([a] -> [a]) -> [a] -> Bool
      Valid hole fits include
        (<*>) :: forall (f :: * -> *) t u.
                 Applicative f =>
                 f (t -> u) -> f t -> f u
          with (<*>) @((->) [a]) @[a] @Bool


我们将了解(<*>)的具体示例化类型,即([a] -> [a] -> Bool) -> ([a] -> [a]) -> [a] -> Bool,以及如何获得该类型的解释。

(<*>) @((->) [a]) @[a] @Bool


显示<*>根据(->) [a] applicative使用,类型为[a]Bool。我们可以描述如下:

(<*>) :: Applicative f => f (t -> u) -> f t -> f u
  where f ~ (->) [a]
        t ~ [a]
        u ~ Bool

相关问题