【问题标题】:Partial application left to right部分应用从左到右
【发布时间】:2011-07-16 14:28:41
【问题描述】:

我昨天开始使用 haskell,但仍然完全迷失在这个美丽的新世界的岸边。现在我遇到了以下问题:

假设我有一些函数可以对整数和另一个变量产生一些魔力:

makeTuple :: Int -> a -> (Int, a)
makeTuple n x = (n, x)

现在我想将此函数应用于列表的所有元素。到目前为止没问题,因为映射也是你在 python 中的日常面包和黄油(我来自哪里)。

makeTupleList :: Int -> [a] -> [ (Int, a) ]
makeTupleList n x = map (makeTuple n) x

据我了解,二进制函数 makeTuple 部分与整数 n 一起应用,因此成为可以映射到 x 的每个元素的一元函数。到目前为止,一切都很好。

但是当 makeTuple 函数有另一个签名时我该怎么办,例如:

makeTuple2 :: a -> Int -> (Int, a)
makeTuple2 x n = (n, x)

通往罗马的方式多种多样:效果相同,但方式不同。现在显然映射不再起作用了:该函数需要一个 Int 并得到一个 a。

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (makeTuple2 n) x -- boolshit

这是意料之中的。我的-也许太pythonic-解决方法是使用另一个函数将参数传递到它们应该去的地方:

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (\x -> makeTuple2 x n) x

问题: 当部分应用的参数不是最左边时,首选的函数式、haskell 风格的部分应用函数的方式是什么?

【问题讨论】:

    标签: haskell partial-application


    【解决方案1】:

    您可以使用flip,它交换函数的第一个和第二个参数。

    makeTupleList2 n x = map (flip makeTuple2 n) x
    

    另一种选择是使用反引号语法创建一个中缀运算符,然后使用运算符部分部分应用它。

    maleTupleList2 n x = map (`makeTuple2` n) x
    

    或者,正如您所说,我们可以使用 lambda 表达式。使用哪一个取决于上下文和个人品味。使用您认为最清楚的任何内容。


    PS:你所做的就是部分应用。柯里化是将带有多个参数的函数(a, b) -> c 转换为柯里化形式 a -> b -> c 以便可以部分应用它的过程。

    【讨论】:

    • 我认为这里的术语有误。反引号将函数转换为中缀运算符。然后使用运算符部分语法执行部分应用程序。反引号与运算符部分无关。
    【解决方案2】:

    在这种特殊情况下,您可以使用flip makeTuple2 n,但这仅适用于具有两个参数的函数。但一般来说,我找不到你的解决方案与 lambda unhaskelly 或太 Pythonic。

    【讨论】:

    • 实际上,假设在flip 的类型中,我们将c = d -> e 替换为(a -> b -> d -> e) -> b -> a -> d -> e。如果您想要一个具有多个参数的无点函数,这会很方便。也就是你要调用flip f b',有两个无点参数。
    • 更一般地,我们可以定义函数$(rotate n),其中n是参数的数量,类似于flip,通过旋转参数(我不确定rotate是否是可通过类型类递归定义)
    • @camccann 啊,整洁。我从来没有真正尝试过自己定义它。
    【解决方案3】:

    您可以将\x -> makeTuple2 x n 替换为flip makeTuple2 n,因为Prelude 定义flip 就像:(我的实现,不是他们的)

    flip :: (a -> b -> c) -> b -> a -> c
    flip f y x = f x y
    

    因此我们得到

    makeTupleList2' = map . flip makeTuple2
    

    或者,看看它如何只是一个元组:

    makeTupleList2'' = map . (,)
    

    另请注意(我不确定这有多有效),您可以使用 zip:

    makeTupleList2''' :: a -> [b] -> [(a, b)]
    makeTupleList2''' = zip . repeat
    

    【讨论】:

      【解决方案4】:

      如果你的函数只是元组构造函数:

      makeTuple x y = (x,y)
      

      (也可以写成makeTuple = (,))那么有一个特殊的扩展名:

      {-# LANGUAGE TupleSections #-}
      makeTupleList2 n x = map (n,) x
      makeTupleList2' n x = map (,n) x     -- Use n as the second component
      

      也可以写成

      makeTupleList2 n = map (n,)
      makeTupleList2' n = map (,n)
      

      否则使用已经建议的方式。

      【讨论】:

      • 不正确,应该是makeTupleList2 n = map (n,),因此是makeTupleList2 = map . (,)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 2022-01-13
      相关资源
      最近更新 更多