代码之家  ›  专栏  ›  技术社区  ›  Tom Huntington

ghci能告诉我们正在使用类的哪个实例吗

  •  2
  • Tom Huntington  · 技术社区  · 1 年前

    这是一些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 b 与有关 a .

    他们无论如何都要让ghci告诉我什么适用性 f 实际上正在这里使用。如果不是的话,哈斯克勒是怎么解释这些东西的。

    1 回复  |  直到 1 年前
        1
  •  3
  •   Joseph Sible-Reinstate Monica    1 年前

    您可以使用 -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) 中的实例 the documentation ).

    或者,你可以在没有GHC帮助的情况下,通过查看类型来解决问题,如下所示:

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

    为了简单起见,我将对后两种类型进行阿尔法转换,以不重用 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] , 必须是 [t] b 必须是 Bool 。一个快速的健全性检查是正确的,就是观察 f b 是的 [t] -> Bool ,在阿尔法等价之后,它是推断为的输出的相同类型GHC allEqual <*> reverse 自从 f 是什么 Applicative 上需要实例,它必须将该实例用于 (->)[t] (将列表作为参数的函数)。正在执行 :instances ((->) [t]) 会给你看 instance Applicative ((->) [t]) -- Defined in ‘GHC.Base’ ,但实际使用的实例更通用,适用于任何类型的函数。找到功能箭头后,执行 :info (->) 将向您展示: instance Applicative ((->) r) -- Defined in ‘GHC.Base’ .