【问题标题】:Filtering in Haskell在 Haskell 中过滤
【发布时间】:2014-12-17 03:50:50
【问题描述】:

我想做的是获取一个元组列表,然后检查任何元组中的任何元素是否与 int 匹配。如果 int 匹配元组中的任一元素,则元组将添加到要返回的列表中。 一旦列表扫描了所有的元组,它将返回一个只匹配 int 的元组列表。

filter1 :: (a -> Bool) -> [(Int, Int)] -> [(Int, Int)]  
filter1 _ [] = []  
filter1 p (x:xs)   
    | p x       = x : filter1 p xs  
    | otherwise = filter1 p xs

这是我目前所拥有的。唯一的问题是它在哪里重复我得到一个错误,因为我正在获取一个元组列表并将其放回一个应该只是一个 int 的地方。

【问题讨论】:

  • 您在这里所做的只是重复了filter 的定义,但是您更改了类型签名。但是,您对类型签名的更改还不够。试试filter1 :: ((Int, Int) -> Bool) -> [(Int, Int)] -> [(Int, Int)]
  • 这里,每个x 都有(Int, Int) 类型,并且您希望对其应用一个返回布尔值的函数。因此,您的p 函数必须具有(Int, Int) -> Bool 类型。 filter :: (a -> Bool) -> [a] -> [a] 的类型在这里说明。您获取as 的列表和从aBool 的函数。在这里,您传递了(Int, Int) 的列表,所以a(Int, Int)
  • @bheklilr 我已经尝试过了,但它对我不起作用
  • 在什么情况下不起作用?你还说你得到了一个错误,但还没有说这个错误真的很容易。请发布您收到的错误消息的全文,GHC 的错误实际上通常非常有用并且有助于解决类型错误。
  • @Sprout (5, 6) 不是(Int, Int) -> Bool 类型,而是(Int, Int) 类型。你必须传递一个函数,而不仅仅是一个“东西”。采用 Ints 元组的函数看起来如何?好吧,让我们看看==== 的类型为a -> a -> Bool,其中 a 必须是相等的。所以现在我们将== 专门用于(Int, Int)(Int, Int) -> (Int, Int) -> Bool。但这是一个元组太多了。我们怎样才能摆脱它?我们可以部分申请==(如果需要,请查看,您需要)。

标签: list haskell recursion filter tuples


【解决方案1】:

如果你不介意,我会给你一些来自 GHCI 的控制台输出。

filter 的类型签名是:

Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]

换句话说,filter 是一个接受两个参数的函数:第一个是从任何类型a 到类型Bool 的函数,下一个是a 元素的列表。然后它会为您提供a 元素的列表(函数会针对这些元素发回True)。

您尝试filter1 (5, 6) [(5, 6), (7, 8)] 的示例代码几乎正确,应该改为:

Prelude> filter (\x -> x == (5, 6)) [(5, 6), (7, 8)]
[(5, 6)]

我们可以使用 Haskell 为运算符提供的特殊语法来编写该谓词。以任何运算符为例,为了便于说明,我们将其称为*+;那么(*+)\x y -> x *+ y 相同,(a *+)\y -> (a *+ y) 相同,(*+ b)\x -> x *+ b 相同。所以我们可以把上面的过滤条件写成简单的((5,6) ==),我们可以通过定义让你的示例代码工作:

Prelude> let filter1 val = filter (val ==)
Prelude> :t filter1
filter1 :: Eq a => a -> [a] -> [a]
Prelude> filter1 (5, 6) [(5, 6), (7, 8)]
[(5,6)]

然而这不是你问的。您的要求是获取一个元组列表,然后检查任何元组中的任何元素是否与 int 匹配。为此,我们还需要接收 int:

Prelude> let tfilter n = filter (\(a, b) -> a == n || b == n)
Prelude> :t tfilter
tfilter :: Eq a => a -> [(a, a)] -> [(a, a)]
Prelude> tfilter 3 [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
[(2,3),(3,4)]

【讨论】:

  • 如何将其编写为函数? tfilter :: Eq a => a -> [(a, a)] -> [(a, a)] tfilter n = filter ((a, b) -> a == n || b == n) |否则 = :t tfilter??
  • :t tfilter 是一个 GHCI 命令:“告诉我tfilter 的类型”。 tfilter 的定义出现在上面;在.hs 文件中,您只需编写:tfilter n = filter (\(a, b) -> a == n || b == n).
【解决方案2】:

箭之路:

filter :: ( a -> Bool ) -> [ (Int, Int) ] -> [ (Int, Int) ]

让我们生成过滤谓词( (Int, Int) -> Bool )

&&& 可用于提供( Int -> Bool, Int -> Bool )

例如,

( (==) &&& (==) ) 3 将产生( (==3), (==3) )

这两个部分可以通过 uncurrying 传递给***

( uncurry (***) ) ( (==3), (==3) ) 将产生 ( (==3) *** (==3) )

这个结果箭头可以用来测试我们的元组值,

( (==3) *** (==3) ) (4,3) 将产生 (False, True)

然后,通过 uncurrying (||),我们得到一个函数,它接受一个布尔元组并给出它的逻辑 OR。

( uncurry (||) ) (False, True) 将产生True

现在我们结束了:

f n tup = uncurry (||) $ ( uncurry (***) . ((==) &&& (==)) ) n tup

延迟uncurry (||) 的组成直到其余时间 部分( uncurry (***) . ((==) &&& (==)) ) 被应用于ntup

f = (uncurry (||) .) . uncurry (***) . ((==) &&& (==))

就是这样。

f 3 (4,5) => False,

f 3 (4,3) => True.

现在我们可以使用 f 谓词和过滤器来获得所需的结果。

tfilter = filter . f

tfilter = filter . (uncurry (||) .) . uncurry (***) . ((==) &&& (==))

tfilter 3 [ (x,y) | x<-[3..6], y<-[1..4] ]

=> [(3,1),(3,2),(3,3),(3,4),(4,3),(5,3),(6,3)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2020-07-29
    相关资源
    最近更新 更多