haskell - uncurry ($) 有什么作用?

标签 haskell functional-programming currying

我正在做一些练习,我必须添加一个函数的类型并解释它的作用。我坚持这个:

phy = uncurry ($)

根据 GHCi,类型是 phy :: (a -> b, a) -> b .我的haskell知识是基础的,所以我真的不知道它是做什么的。

最佳答案

让我们系统地拼出类型部分。我们将从 uncurry 的类型开始。和 ($) :

uncurry :: (a -> b -> c) -> (a, b) -> c
($)     :: (a -> b) -> a -> b

由于目标表达式有 ($)作为 uncurry 的论点,让我们排列它们的类型以反射(reflect)这一点:
uncurry :: (a       -> b -> c) -> (a, b) -> c
($)     :: (a -> b) -> a -> b

整型($)uncurry 的第一个参数类型一致,以及 ($) 的参数和结果类型与 uncurry 的人一致的第一个参数如图所示。这是对应关系:
uncurry's a  <==> ($)'s a -> b
uncurry's b  <==> ($)'s a
uncurry's c  <==> ($)'s b

这有点令人困惑,因为 ab一种类型中的类型变量与另一种类型不同(就像 x 中的 plusTwo x = x + 2x 中的 timesTwo x = x * 2 不同)。但是我们可以重写类型来帮助解释这一点。在像这样的简单 Haskell 类型签名中,任何时候你看到一个类型变量,你都可以用任何其他类型替换它的所有出现,也可以得到一个有效类型。如果您选择新的类型变量(原始类型中没有出现的类型变量),您将得到一个等效类型(可以转换回原始类型);如果您选择非新鲜类型,您将获得适用于更窄范围类型的原始版本的专用版本。

但无论如何,让我们将其应用于 uncurry 的类型。::
-- Substitute a ==> x, b ==> y, c ==> z:
uncurry :: (x -> y -> z) -> (x, y) -> z

让我们使用重写的类型重做“排队”:
uncurry :: (x       -> y -> z) -> (x, y) -> z
($)     :: (a -> b) -> a -> b

现在很明显:x <==> a -> b , y <==> az <==> b .现在,替换 uncurry ($) 中对应类型的类型变量,我们得到:
uncurry :: ((a -> b) -> a -> b) -> (a -> b, a) -> b
($)     ::  (a -> b) -> a -> b

最后:
uncurry ($) :: (a -> b, a) -> b

所以这就是你如何确定类型。它的作用如何?好吧,在这种情况下,最好的方法是查看类型并仔细考虑,弄清楚我们必须编写什么才能获得该类型的函数。让我们用这种方式重写它,让它更加神秘:
mystery :: (a -> b, a) -> b
mystery = ...

因为我们知道mystery是一个参数的函数,我们可以扩展这个定义来反射(reflect):
mystery x = ...

我们也知道它的参数是一对,所以我们可以扩展一点:
mystery (x, y) = ...

因为我们知道 x是一个函数,y :: a , 我喜欢用 f表示“函数”并将变量命名为与其类型相同的名称——这有助于我推理函数,所以让我们这样做:
mystery (f, a) = ...

现在,我们在右手边放什么?我们知道它必须是 b 类型。 ,但我们不知道是什么类型b是(实际上是调用者选择的任何内容,所以我们无法知道)。所以我们必须以某种方式制作一个b使用我们的功能 f :: a -> b和值(value)a :: a .啊哈!我们可以使用以下值调用函数:
mystery (f, a) = f a

我们写了这个函数没有看uncurry ($) , 但事实证明它和 uncurry ($) 做同样的事情确实如此,我们可以证明这一点。让我们从 uncurry 的定义开始。和 ($) :
uncurry f (a, b) = f a b
f $ a = f a

现在,用equals代替equals:
uncurry ($) (f, a) = ($) f a         -- definition of uncurry, left to right
                   = f $ a           -- Haskell syntax rule
                   = f a             -- definition of ($), left to right
                   = mystery (f, a)  -- definition of mystery, right to left

因此,攻击您在 Haskell 中不理解的类型的一种方法是尝试编写一些具有该类型的代码。 Haskell 与其他语言的不同之处在于,这通常是比尝试阅读代码更好的策略。

关于haskell - uncurry ($) 有什么作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15993186/

相关文章:

testing - Yesod/Persistent testing with bracket 模式

haskell - 为什么高阶函数会返回这种(意外的)类型?

haskell - 构建 DAG 以便重用节点

networking - 为什么我在 Racket 上的网络服务器不会多次接收数据?

scala - 在 Scala 中使用 foldLeft 将参数列表应用于 curried 函数

haskell - Haskell 树上折叠的变化

haskell - haskell 中的类型类依赖和 OOP 中的子类型有什么区别?

java - 在流管道中保存到数据库

haskell - 为什么 Haskell 采用一个参数

r - 为什么重复调用 lapply 后闭包中的变量值会丢失?