uncurry ($) 有什么作用? [英] What does uncurry ($) do?

查看:17
本文介绍了uncurry ($) 有什么作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm doing some excersises where I have to add a function's type and explain what it does. I'm stuck with this:

phy = uncurry ($)

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

The type, according to GHCi is phy :: (a -> b, a) -> b. My haskell knowledge is basic so I really have no idea what it does.

推荐答案

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

Let's spell out the type part systematically. We'll start with the types of uncurry and ($):

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

由于目标表达式有 ($) 作为 uncurry 的参数,让我们排列它们的类型以反映这一点:

Since the target expression has ($) as the argument of uncurry, let's line up their types to reflect this:

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

($)的整个类型与uncurry的第一个参数类型对齐,以及($)的参数和结果类型> 与 uncurry 的第一个参数对齐,如图所示.这是通信:

The whole type of ($) lines up with the first argument type of uncurry, and the argument and result types of ($) line up with those of uncurry's first argument as shown. This is the correspondence:

uncurry's a  <==> ($)'s a -> b
uncurry's b  <==> ($)'s a
uncurry's c  <==> ($)'s b

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

This is kinda confusing, because the a and b type variables in one type are not the same as in the other (just like the x in plusTwo x = x + 2 is not the same as the x in timesTwo x = x * 2). But we can rewrite the types to help up reason about this. In simple Haskell type signatures like this, any time you see a type variable you can replace all of its occurrences with any other type get a valid type as well. If you pick fresh type variables (type variables that don't appear anywhere in the original), you get an equivalent type (one that can be converted back to the original); if you pick a non-fresh type you get a specialized version of the original that works with a narrower range of types.

但无论如何,让我们将其应用于 uncurry::

But anyway, let's apply this to the type of uncurry::

-- Substitute a ==> x, b ==> y, c ==> z:
uncurry :: (x -> y -> z) -> (x, y) -> z

让我们使用重写的类型重做排队":

Let's redo the "line up" using the rewritten type:

uncurry :: (x       -> y -> z) -> (x, y) -> z
($)     :: (a -> b) -> a -> b

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

Now it's obvious: x <==> a -> b, y <==> a and z <==> b. Now, substituting uncurry's type variables for their counterpart types in ($), we get:

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

最后:

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

<小时>

这就是您确定类型的方式.它的作用如何?嗯,在这种情况下,最好的方法是查看类型并仔细考虑它,弄清楚我们必须编写什么才能获得该类型的函数.让我们这样重写,让它更神秘:


So that's how you figure out the type. How about what it does? Well, the best way to do that in this case is to look at the type and think about it carefully, figuring out what we'd have to write to get a function of that type. Let's rewrite it this way to make it more mysterious:

mystery :: (a -> b, a) -> b
mystery = ...

既然我们知道 mystery 是一个参数的函数,我们可以扩展这个定义来反映:

Since we know mystery is a function of one argument, we can expand this definition to reflect that:

mystery x = ...

我们也知道它的参数是一对,所以我们可以扩展一点:

We also know that its argument is a pair, so we can expand a bit more:

mystery (x, y) = ...

既然我们知道 x 是一个函数,而 y :: a,我喜欢用 f 来表示函数"和命名变量与其类型相同——这有助于我推理函数,所以让我们这样做:

Since we know that x is a function and y :: a, I like to use f to mean "function" and to name variables the same as their type—it helps me reason about the functions, so let's do that:

mystery (f, a) = ...

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

Now, what do we put in the right hand side? We know it must be of type b, but we don't know what type b is (it's actually whatever the caller chooses, so we can't know). So we must somehow make a b using our function f :: a -> b and value a :: a. Aha! We can just call the function with the value:

mystery (f, a) = f a

我们写这个函数没有看uncurry($),但结果证明它和uncurry($)做了同样的事情,我们可以证明它.让我们从uncurry($)的定义开始:

We wrote this function without looking at uncurry ($), but it turns out that it does the same thing as uncurry ($) does, and we can prove it. Let's start with the definitions of uncurry and ($):

uncurry f (a, b) = f a b
f $ a = f a

现在,用等号代替等号:

Now, substituting equals for 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 与其他语言的不同之处在于,这通常是比尝试阅读代码更好的策略.

So one way to attack a type that you don't understand in Haskell is to just try and write some code that has that type. Haskell is different from other languages in that very often this is a better strategy than trying to read the code.

这篇关于uncurry ($) 有什么作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆