【问题标题】:Haskell filter function with multiple parameters具有多个参数的 Haskell 过滤器函数
【发布时间】:2017-10-08 15:34:33
【问题描述】:

我正在尝试学习 Haskell,想知道如何使用一个接受多个参数的函数过滤给定列表,将列表中的每个元素与其他不变的元素一起传递给函数,以创建一个新列表。

我知道我可以这样做以使用 bool 函数来过滤列表:

newList = filter theFunction aList

但是当 theFunction 采用其他参数时会发生什么:

theFunction -> elementOfAList -> Int -> Bool 

那么我如何过滤列表中的每个元素,同时将另一个元素解析到函数中?任何帮助将不胜感激:)

Edit -> 为了提供更多信息,如果我想获得 [1..10] 中的整数列表,通过一个接受两个整数的函数进行过滤,如果第一个整数更小则返回 true,如何我可以这样做吗?

【问题讨论】:

  • 不清楚你的意思,请添加一些代码/伪代码来解释你想如何使用它
  • 您的编辑:我的回答的第一部分完全适用。也就是说,如果您使用相同的 int,例如 theFunction x i = x < i,然后是 filter (flip theFunction 5) aList,则在结果列表中保留 aList 中小于 5 的所有元素。
  • 看起来这不是过滤而是折叠工作。你可以试试(==) <$> foldr1 (\x y -> bool (minBound :: Int) x (x <= y)) <*> head。其中bool 是来自Data.Bool.bool 的三元运算符,类型为a -> a -> Bool -> a
  • @Redu consider [1,2,3,1]: 3 <= 2 是假的,所以会产生minBound - 为什么? --- 此外,foldr1 的实现(oldnew)保证仅使用现有值调用缩减函数。并且minimum 已经存在。
  • @Redu 但对于[minBound, 3, 1],您的函数将返回...True。 ---我把这个问题看作是关于一般使用模式的更多信息。 --- ascending = and . (zipWith (<=) <*> drop 1).

标签: haskell filter parameters predicate partial-application


【解决方案1】:

在这种情况下,您使用部分应用的谓词函数,像这样

-- theFunction :: elementOfAList -> Int -> Bool       -- "::" means, "is of type"
newList = filter (flip theFunction i) aList

因为

flip theFunction i x = theFunction x i

根据flip的定义,所以flip theFunction的类型为Int -> elementOfAList -> Bool

flip ::       (a -> b   -> c   ) -> b -> a -> c
theFunction :: a -> Int -> Bool
flip theFunction ::               Int -> a -> Bool
flip theFunction  (i ::  Int)         :: a -> Bool

其中i 是在别处定义的某个Int 值。 a 是一个类型变量,即它可以是任何类型,例如列表元素的类型(即对于列表aList :: [a],每个元素都具有相同的类型,a)。

例如,使用theFunction x i = x < i,您可以调用filter (flip theFunction 5) aList,在结果列表中保留aList 中小于5 的所有元素。通常这将写为filter (< 5) aList,使用operator sections (其中(< 5) 是一个例子,完全等同于flip theFunction 5)。


上述过滤将使用相同的Inti为列表aList的每个元素x调用theFunction。如果您想重新计算 Int,则使用另一种模式(即高阶函数)完成,

mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

假设您想将theFunction 找到的所有元素保存在一个整数列表中。然后你可以这样做

theFunction :: elementOfAList -> Int -> Bool
foo :: Int -> [Int] -> [Int]
foo i xs = concat (snd (mapAccumL g i xs))    -- normally written as
        -- concat $ snd $ mapAccumL g i xs     -- or 
        -- concat . snd $ mapAccumL g i xs      -- or even
        -- concat . snd . mapAccumL g i $ xs
  where
  g acc x   -- g :: (acc -> x -> (acc, y))  according to mapAccumL's signature
    | theFunction x acc = (x, [x])   -- include `x` in output, and update the acc
    | otherwise         = (acc, [])  -- keep the accumulated value, and skip this `x`

因为xacc 都用于相同的角色(元组的第一个元素),所以它们必须是相同的类型。

【讨论】:

  • 也许从教学上讲,使用 lambda 表达式而不是 flip 会更有效。
  • @dfeuer 我更喜欢组合定义。 \ -> 看起来像是更繁重的语法。
  • 我都不喜欢,我会写成filter (`theFunction`i) aList。 (但如果 theFunction 首先以翻转的形式定义,当然会更好。)
  • @leftaroundabout 我也是((`op` v) 的东西)。我的意思是在这里进行说明,因为其他两个选项都涉及需要向学习者解释/处理的新 语法theFunction 大概是 OP已经 拥有的东西,a.o.t.专门为此用途定义它。
猜你喜欢
  • 2018-04-11
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 2018-11-03
  • 2019-12-29
  • 2014-06-12
相关资源
最近更新 更多