我正在做一些练习,我必须添加一个函数的类型并解释它的作用。我坚持这个:
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
这有点令人困惑,因为
a
和 b
一种类型中的类型变量与另一种类型不同(就像 x
中的 plusTwo x = x + 2
与 x
中的 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 <==> a
和 z <==> 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/