Haskell 如何基于一元模式匹配进行过滤?

Haskell 如何基于一元模式匹配进行过滤?,haskell,pattern-matching,filtering,maybe,Haskell,Pattern Matching,Filtering,Maybe,我有以下问题: 给定一个类型data T=T(可能是Int),我如何筛选一个列表以获取非Nothing值 输入 a = [T (Just 3), T Nothing, T (Just 4)] b = [T (Just 3), T (Just 4)] 所需输出 a = [T (Just 3), T Nothing, T (Just 4)] b = [T (Just 3), T (Just 4)] 我试过这样的方法: b = filter (\x-> x@(Just t)) a …

我有以下问题:

给定一个类型
data T=T(可能是Int)
,我如何筛选一个列表以获取非
Nothing

输入

a = [T (Just 3), T Nothing, T (Just 4)]
b = [T (Just 3), T (Just 4)]
所需输出

a = [T (Just 3), T Nothing, T (Just 4)]
b = [T (Just 3), T (Just 4)]
我试过这样的方法:

b = filter (\x-> x@(Just t)) a 
…认为我可以根据模式匹配进行筛选,但我得到了错误:

Pattern syntax in expression context: x@(Just t)
    Did you mean to enable TypeApplications?

稍后,您将能够解压缩内部值(仅在
)并相应地使用它

我认为在这里我们可以更好地使用列表理解的模式匹配语义:

result = [ e | e@(T (Just _)) <- a]

因此,这将不仅“过滤”值,而且同时解包。因此,
T Nothing
s被忽略,只有被包装的
T(Just e)
s被保留,相应的
e
s最终出现在列表中。

我认为这里我们可以更好地使用列表理解的模式匹配语义:

result = [ e | e@(T (Just _)) <- a]

因此,这将不仅“过滤”值,而且同时解包。因此,
T Nothing
s被忽略,只有包装的
T(Just e)
s被保留,相应的
e
s在列表中结束。

模式匹配只在函数的参数中起作用,而不是在主体中起作用。您需要匹配的模式是
T
,使用类似
maybe
的反同构将包装值转换为布尔值

Prelude> a = [T (Just 3), T Nothing, T (Just 4)]
Prelude> filter (\(T x) -> maybe False (const True) x) a
[T (Just 3),T (Just 4)]
但是,请注意,
maybe False(const True)
已经定义为
数据。maybe.isJust

Prelude> import Data.Maybe
Prelude> filter (\(T x) -> isJust x) a
[T (Just 3),T (Just 4)]
如果有一些类型为
T->Maybe Int
的函数与
isJust
组合,则可以简化谓词。例如:

Prelude> data T = T { getT :: Maybe Int } deriving Show
Prelude> a = [T (Just 3), T Nothing, T (Just 4)]
Prelude> filter (isJust . getT) a
[T {getT = Just 3},T {getT = Just 4}]

模式匹配只适用于函数的参数,而不适用于主体。您需要匹配的模式是
T
,使用类似
maybe
的反同构将包装值转换为布尔值

Prelude> a = [T (Just 3), T Nothing, T (Just 4)]
Prelude> filter (\(T x) -> maybe False (const True) x) a
[T (Just 3),T (Just 4)]
但是,请注意,
maybe False(const True)
已经定义为
数据。maybe.isJust

Prelude> import Data.Maybe
Prelude> filter (\(T x) -> isJust x) a
[T (Just 3),T (Just 4)]
如果有一些类型为
T->Maybe Int
的函数与
isJust
组合,则可以简化谓词。例如:

Prelude> data T = T { getT :: Maybe Int } deriving Show
Prelude> a = [T (Just 3), T Nothing, T (Just 4)]
Prelude> filter (isJust . getT) a
[T {getT = Just 3},T {getT = Just 4}]

如果您想在
T
s列表中获得
Int
值的列表(如此键入
[T]->[Int]
),那么从
数据中。也许
已经几乎完全满足了您的要求。除此之外,还需要一个类型为
T->Maybe Int

import Data.Maybe ( mapMaybe )

data T = T (Maybe Int)
  deriving (Eq, Show)

unT :: T -> Maybe Int
unT (T x) = x

filterTs = mapMaybe unT
然后:

在我看来,将此筛选操作的类型设置为
[T]->[Int]
比返回包含非
无值的
T
值更有用;原因是,即使您将
a
过滤到
[T(仅3),T(仅4)]
,那么稍后处理该问题的代码仍然必须在
上进行模式匹配,以获得
Int
值,即使您知道永远不会有
1,因为
T
仍然硬编码为不包含任何内容

作为一般规则,如果您正在过滤(或默认或其他)以保证没有一个案例,那么您应该考虑将其转换为不再具有这种情况的类型。它通常使生成的数据更容易处理(例如,不需要模式匹配或

fmap
s进入冗余层),并且有助于避免错误

还有
catMaybes::[maybea]->[a]
,它可以“过滤出
没有映射的任何内容”,但是由于您映射到unapp,因此
T
构造函数
mappea
更适合



1和这种“我知道这里永远不会有
什么都没有,所以我不必处理它”的情况是一个非常丰富的bug源,当将来隐藏不变的东西发生变化时,很容易被破坏。因此,实际上编写代码来利用
什么都没有
“不可能”的知识,这甚至不是一个好主意;你仍然应该处理这两种情况

如果您想在
T
s列表中获得
Int
值的列表(如此键入
[T]->[Int]
),那么从
数据中。也许
已经几乎完全满足了您的要求。除此之外,还需要一个类型为
T->Maybe Int

import Data.Maybe ( mapMaybe )

data T = T (Maybe Int)
  deriving (Eq, Show)

unT :: T -> Maybe Int
unT (T x) = x

filterTs = mapMaybe unT
然后:

在我看来,将此筛选操作的类型设置为
[T]->[Int]
比返回包含非
无值的
T
值更有用;原因是,即使您将
a
过滤到
[T(仅3),T(仅4)]
,那么稍后处理该问题的代码仍然必须在
上进行模式匹配,以获得
Int
值,即使您知道永远不会有
1,因为
T
仍然硬编码为不包含任何内容

作为一般规则,如果您正在过滤(或默认或其他)以保证没有一个案例,那么您应该考虑将其转换为不再具有这种情况的类型。它通常使生成的数据更容易处理(例如,不需要模式匹配或

fmap
s进入冗余层),并且有助于避免错误

还有
catMaybes::[maybea]->[a]
,它可以“过滤出
没有映射的任何内容”,但是由于您映射到unapp,因此
T
构造函数
mappea
更适合



1和这种“我知道这里永远不会有
什么都没有,所以我不必处理它”的情况是一个非常丰富的bug源,当将来隐藏不变的东西发生变化时,很容易被破坏。因此,实际上编写代码来利用
什么都没有
“不可能”的知识,这甚至不是一个好主意;你仍然应该处理这两种情况

这回答了问题的字母,但我敢打赌,
[e|T(只是e)是的,这正是问题的答案