【问题标题】:How to partially apply the flip function?如何部分应用翻转功能?
【发布时间】:2012-02-25 03:12:08
【问题描述】:

我对翻转的“部分”应用可能会做什么有点困惑。

由于flip函数的类型是:

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

不用括号我们可以写成:

flip :: a -> b -> c -> b -> a -> c

我如何才能将其部分应用于仅第一个参数a?获取具有以下类型的函数:

flipa ::     b -> c -> b -> a -> c

还是没有意义?

例如,如果我有类似的东西:

let foo a b = (Just a, b)
:t foo
> foo:: a -> t -> (Maybe a, t)

部分应用它是有意义的:

let a = foo 1
:t a
a :: t -> (Maybe Integer, t)

【问题讨论】:

  • (->) 是右关联的,而不是左关联的:您描述的 flipa 是一个完全不同的函数(AFAIK 类型规定它必须是 flipa _ x _ _ = x)。
  • 为什么这两个不等价的另一种观点:让我们以f :: (a → a) → ag :: a → a → a 为例。通过 Curry-Howard 同构,g 表示定理a ⇒ a ⇒ a,即如果a 为真,则a 暗示a(这是真的;它可以从a ⇒ (b ⇒ a) 推导出来(直觉逻辑公理) )。另一方面,(a ⇒ a) ⇒ a 没有告诉我们任何关于a 的信息(如果a 暗示a 那么a;但正如你所看到的,a 也可能是假的,a ⇒ a 仍然成立)。确实,如果你有f :: (a → a) → a,你可以证明false为真:boom :: False; boom = f id(其中False为空数据类型)

标签: haskell


【解决方案1】:

这没有意义。签名

f :: a -> b -> c

等价于

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

并不等同于

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

这个约定是为什么你可以首先在 Haskell 中部分应用函数的原因。由于默认情况下所有函数都是柯里化的,所以签名f :: a -> b -> c可以解释为

f 接受 ab,并返回 c

或者可以同样有效地解释为

f 接受 a,并返回一个接受 b 并返回 c

的函数

【讨论】:

  • 嗯.. 在我更新的问题中看到的一个简单函数怎么样。
  • 您对该功能有什么疑问?
  • “部分应用”是“currying”的有效同义词
  • 嗯,是的,考虑到函数 (a × b × c) → d,currying 将其转换为 a → b → c → d,而部分应用程序将任何参数固定为函数 (b × c) → d(或其他对,取决于所应用的参数) .
  • @drozzy:你可以而且事实上你已经做到了!假设翻转的类型为d → b → a → c,其中d 必须是a → b → c 类型的函数。如果你将flip 应用到d 类型的函数f,你会得到一个新的函数b → a → c 并固定了d 参数。
【解决方案2】:

(a -> b -> c) -> b -> a -> ca -> b -> c -> b -> a -> c 不同,因为 -> 运算符是右关联的,而不是左关联的。因此,部分应用flip 毫无意义,因为它首先只有一个参数。

此外,您的示例没有多大意义,因为它仍会产生一个采用a 的输出函数,而您可能不希望这样做。但是如果你把它拿出来,你会得到一个函数,它接受一个一元函数并产生完全相同的一元函数,所以只需部分应用原始函数就可以了。

【讨论】:

  • 我看到三个参数:D(但肯定不是五个!)
  • 这取决于你如何看待它,但在正常使用中,flip 有一个参数并产生一个接受两个参数的函数。当然,在 Haskell 中,因为柯里化,这与部分应用带三个参数的函数完全相同。
【解决方案3】:

正如其他人所指出的,(a -> b -> c) -> b -> a -> c 的类型a -> b -> c -> b -> a -> c 相同。

但是,它(a -> b -> c) -> (b -> a -> c) 相同。

这表明flip 是一个将单个参数作为输入的函数,因此不能部分应用*。


*:从 flip 返回一个 b -> a -> c 类型的函数的角度来看,这不是 Haskell 中唯一有效的观点。

【讨论】:

  • 为什么和(a -> b -> c) -> (b -> a -> c)一样?为什么你可以带最后一个三元组的括号,而不是第一个?
  • @drozzy -- Learn You a Haskellbecause functions are curried by default, the second pair of parentheses is really unnecessary, because -> is right associative by default. (a -> b -> c) -> (b -> a -> c) is the same as (a -> b -> c) -> (b -> (a -> c)), which is the same as (a -> b -> c) -> b -> a -> c。所以这是因为->的关联性。
  • @drozzy:那是因为-> 是右结合的。换句话说,a → (b → (c → (d → e)))a → b → c → d → e 相同。例如,实数除法是左关联的,这意味着((5 / 4) / 3) / 2 = 5 / 4 / 3 / 2 但不是5 / (4 / (3 / 2))。编辑:也许更具启发性的例子:(5 / 4) / (3 / 2) ≠ 5 / 4 / 3 / 2
猜你喜欢
  • 2013-01-02
  • 1970-01-01
  • 2011-06-27
  • 1970-01-01
  • 2019-10-14
  • 2017-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多