【问题标题】:Rewriting an uncurried function haskell重写一个非咖喱函数haskell
【发布时间】:2013-10-24 00:58:41
【问题描述】:

我一直在学习 uncurrying 和在 haskell 函数中应用 $,但我仍然在将 uncurried 函数转换为不那么神秘的东西时遇到问题。

给我的功能是

apple = map $ uncurry $ flip ($)

我意识到这需要一个元组列表并将元组中的相应函数应用于内部变量。所以我正在尝试将其重写为

apple ls = foldr function _ ls
    where function (a,b) c = (uncurry b) (a,c)

我得到 _ 作为解析错误的错误,我不知道要使用哪个起点。我需要使这种多态性,并且我意识到这很可能不会使它变得不那么神秘。有任何想法吗?他们将不胜感激

【问题讨论】:

  • 原始apple 的主要定义是基于map (这是有道理的,因为它需要一个列表并对列表的每个元素“做某事”来给你一个列表结果)。所以最直接的重新实现它的方法是使用map,而不是foldr。你可以使用foldr,因为foldr更通用,可以用来实现map。但在任何基于foldr 的解决方案中,您基本上必须 包含map 的重新实现,这会增加复杂性并且不会帮助您使其更清晰。

标签: function haskell tuples


【解决方案1】:

苹果有这种类型

apple :: [(a, a->b)] -> [b]

我们可以改写成

apple ls = map (\(a, f) -> f a) ls

所以用foldr 写这个是非常可行的,

apple ls = foldr (\(a, f) rest -> f a : rest) [] ls

或者,我们可以将其重写为无点

apple = foldr ( (:) . (uncurry . flip $ ($)) ) []

解析错误的原因是_ 是“我不关心的变量”的特殊语法。这让你可以写出类似的东西

 foo _ _ _ _ a = a

并且不会得到关于重复变量的错误。基本上我们只是用起始空列表填充_,并修复function,使其附加到c,而不是尝试将其应用到a

如果我想以最清晰的方式写这个,那么原文

apple = map . uncurry . flip $ ($)

挺好看的。

【讨论】:

  • 你的第一个类型签名应该是apple :: [(a, a->b)] -> [b],对吗?
  • 尽管它不是免费的,但我想说最清晰的定义实际上是:apple xfs = [f x | (x, f) <- xfs] 比其他任何一个都更短更清晰。
  • @NeilBrown 但他要求“uncurring”,而您的版本根本不使用它!
【解决方案2】:

理解的关键是消除复杂性。

因此,我建议您先处理单个元组。编写如下函数:

 tapp :: (a, a ->b) -> b

根据 ($) 和 flipuncurry。 (为了更简单,您可以先对元组 (a -> b, a) 执行此操作。

接下来,让自己弄清楚 map 是如何工作的:如果你有一个函数 f :: (a -> b),那么 map f 将是一个函数 [a] -> [b]。因此map tapp 做你想做的事。

您现在可以将map (tapp) 中的tapp 替换为它的定义(这是引用透明的好处)。 这应该带你回到你原来的表情。或多或少如此,因为例如:

f $ g h

可以写

f (g h)

(f . g) h

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2022-01-02
    相关资源
    最近更新 更多