【问题标题】:Haskell function composition, type of (.)(.) and how it's presentedHaskell 函数组合、(.)(.) 的类型及其呈现方式
【发布时间】:2013-04-18 14:41:22
【问题描述】:

所以我知道:

(.) = (f.g) x = f (g x)

它的类型是 (B->C)->(A->B)->A->C 但是呢:

(.)(.) = _? = _?

这是如何表示的?我想到了:

(.)(.) = (f.g)(f.g)x = f(g(f(g x))) // this
(.)(.) = (f.g.h)x = f(g(h x)) // or this

但就我试图获取它的类型而言,GHCi 告诉我的内容是不正确的。 那么两个“_”是什么?

还有 - 函数/运算符 $ 做什么?

【问题讨论】:

  • 不知道要不要给(.)(.)(.).(.)的名字加标签?

标签: haskell types operator-keyword function-composition


【解决方案1】:

首先,你的符号很草率。

(.) = (f.g) x = f (g x)  -- this isn't true

什么是真的:

(.) f g x = (f.g) x = f (g x)
(.) = \f g x -> f (g x)

它的类型由下式给出

(.) :: (b -> c) -> (a -> b) -> a -> c
       -- n.b. lower case, because they're type *variables*

同时

(.)(.) :: (a -> b -> d) -> a -> (c -> b) -> c -> d
          -- I renamed the variables ghci gave me

现在我们开始锻炼

(.)(.) = (\f' g' x' -> f' (g' x')) (\f g x -> f (g x))
       = \g' x' -> (\f g x -> f (g x)) (g' x')
       = \g' x' -> \g x -> (g' x') (g x)
       = \f y -> \g x -> (f y) (g x)
       = \f y g x -> f y (g x)
       = \f y g x -> (f y . g) x
       = \f y g -> f y . g

还有($)?

($) :: (a -> b) -> a -> b
f $ x = f x

($) 只是函数应用程序。但是通过并置的函数应用优先级较高,而通过($) 的函数应用优先级较低。

square $ 1 + 2 * 3 = square (1 + 2 * 3)
square 1 + 2 * 3 = (square 1) + 2 * 3  -- these lines are different

【讨论】:

  • (.)(.) 并不是真正的运算符,而是表达式。你可以写(.) (.) f y g
  • @RippeR no,id 是多态的,而 succ 仅在枚举上定义。由于a -> b 不是枚举,(.)(.) succ succ succ 3 没有意义。 (.) (.) id = (.)
  • @RippeR (.) (.) f y g x = f y (g x),就像我的回答一样。
  • @RippeR y 不是一个函数。再次阅读我为(.)(.) 提供的类型签名。
  • 如果我至少能理解其中的 10% 会容易得多... ;) 我认为这对我来说太过分了,至少现在...这只是为了我(一个所有编程经验都是 C++ 和类似语言的人)。但是无论如何,谢谢,我明天会尝试从中得到一些东西(今天对我来说是后者;))。顺便提一句。您知道适合初学者(或使用 C++/C#/Java/PHP 等编程的人)的好的教程或书籍吗?你听起来很擅长主题,所以也许你知道一些好东西。 ;)
【解决方案2】:

正如 dave4420 所说,

(.) :: (b -> c) -> (a -> b) -> a -> c

那么(.) (.) 的类型是什么? dave4420 跳过了那部分,所以这里是:(.) 接受 b -> c 类型的值作为它的第一个参数,所以

(.) :: (   b     ->       c             ) -> (a -> b) -> a -> c
(.) ::  (d -> e) -> ((f -> d) -> f -> e)

所以我们有b ~ d->ec ~ (f -> d) -> f -> e(.)(.) 的结果类型是(a -> b) -> a -> c。代入,我们得到

(a -> d -> e) -> a -> (f -> d) -> f -> e

重命名,我们得到(a -> b -> c) -> a -> (d -> b) -> d -> c。这是一个函数f,它需要一个二元函数g、一个值x、一个一元函数h和另一个值y

f g x h y = g x (h y)

这是实现这种类型的唯一方法:g x :: b -> ch y :: bg x (h y) :: c,根据需要。

当然,在 Haskell 中,“一元”函数需要一个 或多个 参数;类似地,“二进制”函数需要两个 或更多 参数。但不少于两个(因此使用例如succ 是不可能的)。


我们也可以通过编写方程式来解决这个问题,combinators-style1Equational reasoning is easy:

(.) (.) x y z w q = 
((.) . x) y z w q =
(.) (x y) z w q =
(x y . z) w q =
x y (z w) q 

我们只是根据需要将尽可能多的变量放入混合中,然后来回应用定义。 q这里是一个额外的,所以我们可以把它扔掉,得到最终的定义,

_BB x y z w = x y (z w)

(巧合的是,(.) 被称为B-combinator)。


1a b c = (\x -> ... body ...)等价于a b c x = ... body ...,反之亦然,前提是x不出现在{a,b,c}中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    • 2013-05-10
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    相关资源
    最近更新 更多