理解`flip($)`的类型

时间:2014-11-25 02:07:32

标签: haskell

查看($)flip的类型:

ghci> :t ($)
($) :: (a -> b) -> a -> b

ghci> :t flip
flip :: (a -> b -> c) -> b -> a -> c

您能否向我解释flip ($)如何签名?

ghci> :t flip ($)
flip ($) :: b -> (b -> c) -> c

3 个答案:

答案 0 :(得分:12)

非常简单:

($) :: (a -> b) -> a -> b
       |______|    |    |
           |       |    |
flip  ::  (a    -> b -> c) -> b -> a -> c

因此,我们基本上将(a -> b -> c)(a -> b) -> a -> b统一起来。为清楚起见,我们将(a -> b -> c)重命名为(r -> s -> t)

($) :: (a -> b) -> a -> b
       |______|    |    |
           |       |    |
flip  ::  (r    -> s -> t) -> s -> r -> t

因此:

  1. r(a -> b)结合使用。
  2. sa结合使用。
  3. tb结合使用。
  4. 因此:

    flip ($) :: s -> r -> t
             :: a -> (a -> b) -> b
    

    这相当于:

    flip ($) :: b -> (b -> c) -> c
    

    这就是它的全部内容。


    修改

    1. flip函数有一个参数(a -> b -> c)和一个返回值b -> a -> c
    2. 当您编写flip ($)时,($)函数将成为flip函数的第一个参数。
    3. 因此,($)的类型签名为unified,其参数类型为flip
    4. 统一是将两个术语合并为一个术语的过程。
    5. 在这种情况下,这两个词是(a -> b -> c)(a -> b) -> a -> b
    6. 要将它们统一为一个词(a -> b -> c)首先重命名为(r -> s -> t),然后用r代替(a -> b)s代替a }和t代替b
    7. 例如,我们可以编写一个Prolog程序来统一术语:

      % fun(R, fun(S, T))         is equivalent to (r -> s -> t).
      % fun(fun(A, B), fun(A, B)) is equivalent to (a -> b) -> a -> b.
      
      ?- fun(R, fun(S, T)) = fun(fun(A, B), fun(A, B)).
      R = fun(A, B),
      S = A,
      T = B.
      

      可以在此处找到统一算法:http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse5

      在统一term1term2时总结统一算法:

      1. 如果term1term2是常量,那么当且仅当它们是相同的常量时,它们才会统一。例如,Int仅与常量Int统一。它并不与常量Char统一。
      2. 如果term1是变量而term2是非变量,那么term1将被term2实例化(即term1 := term2)。例如,aInta := Int统一。
      3. 如果term2是变量而term1是非变量,那么term2将被term1实例化(即term2 := term1)。例如,Intbb := Int统一。
      4. 如果term1term2都是变量,那么它们都会相互实例化,并且据说它们共享值(即term1 := term2term2 := term1)。例如,统一时,ab将成为同一个变量。
      5. 如果term1term2是复杂的术语(例如term1Either a Intterm2Either Char b),那么他们会统一除非:
        1. 它们具有相同的类型构造函数。例如,Maybe IntMaybe Char具有相同的类型构造函数。但是,Maybe Int[Int]没有。
        2. 他们相应的论点统一起来。例如,在Either a IntEither Char b中,参数与a := Charb := Int统一。
        3. 变量实例化是兼容的。例如,在将Either a aEither Char Int统一时,我们先是a := Char,然后是a := Int。这是不兼容的。因此这两个词没有统一。
      6. 当且仅当它与之前统一的5个条款相符时,两个术语统一起来。

答案 1 :(得分:4)

排列类型的相应组件:

($)  ::  (a -> b) -> a -> b
flip :: (a        -> b -> c) -> b -> a -> c

重要规则:在任何类型的签名中,您可以将类型变量的每个匹配项替换为不会出现在同一签名中的任何位置,并获得与原始类型完全等效的类型。 (类型不关心类型变量的名称,只关注哪些变量相同以及哪些变量在同一签名中是不同的。)因此,我们可以在flipa := x中稍微重命名类型变量,b := yc := z),它们的类型相同:

($)  ::  (a -> b) -> a -> b
flip :: (x        -> y -> z) -> y -> x -> z

略有不同的规则:在任何类型的签名中,我们可以用任何类型替换类型变量的所有实例,并获得该类型的专用版本。我们将flip专门化为使其与($)兼容的类型。我们通过替换x := (a -> b)y := az := b

来实现这一目标
($)   ::  (a -> b) -> a -> b
 flip :: ((a -> b) -> a -> b) -> a -> (a -> b) -> b

既然这个专业版flip的第一个参数的类型与($)的类型匹配,我们就可以找出flip ($)的类型:

 flip ($) :: a -> (a -> b) -> b

现在我们替换b := c,然后替换a := b

 flip ($) :: b -> (b -> c) -> c

答案 2 :(得分:2)

未翻转的$在其右侧获取a类型的值,并将其应用于左侧的(a -> b)函数:func $ value与{{func value相同1}}。

翻转$在其左侧采用b类型的值,并将右侧的函数(b->c)应用于它:value `flip ($)` func与{{func value相同1}}。