首页 > 解决方案 > 使用列表理解的带有谓词的自定义过滤器函数

问题描述

我需要开发自己的过滤器功能,类似于filter在 Haskell 中的工作方式,但使用列表理解和谓词。所以我会lcFilter (>3) [1,2,3,4,5,6,10,444,3]输入 ghci,它会打印所有大于 3 的数字。

我的代码基于我擅长的递归示例,但我似乎无法转换为列表理解。无论我在其中放入什么,[x | x<-xs, p]它都会接缝总是引发编译器错误。我知道这p部分是错误的。我试过了==pxs==p几乎所有我能想到的。这让我认为其他部分可能是错误的,但我真的不确定。

这是我的函数的代码lcFilter。我不确定它是否部分或全部是错误的,所以我发布了整个内容。

lcFilter :: (a -> Bool) -> [a] -> [a]
lcFilter _ [] = []
lcFilter p (x:xs) = [x | x<-xs, p]

如果我键入lcFilter (>3) [1,2,3,4,5]它应该[4,5]像标准的 Haskellfilter函数一样打印。

标签: haskellfilterlist-comprehensionhigher-order-functions

解决方案


这很简单

      [x | x <- xs, p x]

因为p :: a -> Bool, 和xs :: [a], 要获得布尔值,我们需要函数应用于参数;并且通过我们拥有的列表理解语义x :: a

类型推断的应用规则是

            x :: a
          p   :: a -> b
         ---------------
          p x ::      b

而且您不需要模式匹配,列表理解会解决这个问题。

所以总的来说,它是

lcFilter :: (a -> Bool) -> [a] -> [a]
lcFilter p xs = [x | x <- xs, p]

列表推导很有趣。他们遵循的一条规则是

    [ ... | x <- (xs            ++                ys), .... ]  ===
    [ ... | x <-  xs, ....  ]   ++   [ ... | x <- ys , .... ]

结果,我们也有

    [ ... | x <- ([y]           ++                ys), .... ]  ===
    [ ... | x <-  [y], .... ]   ++   [ ... | x <- ys , .... ]  ===
    [ ...{x/y} | ....{x/y}  ]   ++   [ ... | x <- ys , .... ]  

where的{x/y}意思是“全部替换”xy。因此,[a,b,...,n]您的定义将列表转换为

    [  a,           b,          ...,    n        ]             ===>
    [  a | p a] ++ [b | p b] ++ ... ++ [n | p n  ]

这可以进一步理解为 / 作为monadsmonoids概念的一个很好的说明 / ,但我们将把它留到另一天。:)


推荐阅读