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

phy = uncurry ($)

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

最佳答案

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

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

由于目标表达式将($)作为uncurry的参数,因此让我们排列它们的类型以反映这一点:
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 -> by <==> 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是一个参数的函数,所以我们可以扩展此定义以反映这一点:
mystery x = ...

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

因为我们知道x是一个函数和y :: a,所以我喜欢使用f来表示“功能”,并使用与它们的类型相同的名称来命名它-这有助于我对这些功能进行推理,因此我们可以这样做:
mystery (f, a) = ...

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

我们编写此函数时没有考虑uncurry ($),但事实证明它的作用与uncurry ($)相同,并且我们可以证明这一点。让我们从uncurry($)的定义开始:
uncurry f (a, b) = f a b
f $ a = f a

现在,用等于代替等于:
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/

10-10 21:36