我有以下问题:
给定类型data T = T (Maybe Int)
,如何过滤获取非Nothing
值的列表?
输入
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?
I want to之后可以解包内部值(在Just
下)并相应地使用它。
答案 0 :(得分:4)
我认为在这里我们可以更好地使用列表理解的模式匹配语义:
result = [ e | e@(T (Just _)) <- a]
因此,我们在此处枚举e
中的元素a
,如果与T (Just _)
匹配的模式成功,我们将在结果列表中产生它。
但是,如果您希望解包封装在T (Just x)
中的值,则我们可以执行模式匹配,并产生包装的元素:
result = [ e | T (Just e) <- a]
因此,这不仅可以“过滤”值,还可以同时解压缩。因此,T Nothing
被忽略,只有保留的T (Just e)
被保留,并且相应的e
最终出现在列表中。
答案 1 :(得分:3)
如果您想在Int
列表中键入T
(因此键入[T] -> [Int]
)中的Data.Maybe
值列表,则从T -> Maybe Int
中选择mapMaybe
已经几乎可以满足您的要求。最重要的是,类型为import Data.Maybe ( mapMaybe )
data T = T (Maybe Int)
deriving (Eq, Show)
unT :: T -> Maybe Int
unT (T x) = x
filterTs = mapMaybe unT
λ a = [T (Just 3), T Nothing, T (Just 4)]
a :: [T]
λ filterTs a
[3,4]
it :: [Int]
然后:
[T] -> [Int]
我认为让此过滤操作为T
类型比使它返回包含非{Nothing
值的a
值更有用;原因是,即使您将[T (Just 3), T (Just 4)]
过滤到Just
,处理以后的 still 的代码也必须在Int
上进行模式匹配以获取即使您知道永远不会有Nothing
1 ,因为T
仍被硬编码为包含Nothing
。
作为一般规则,如果要过滤(或默认设置等)以保证不存在大小写,则应考虑转换为不再包含大小写的类型。它通常使结果数据更易于处理(例如,无需模式匹配或fmap
即可进入冗余层),并有助于避免错误。
还有catMaybes :: [Maybe a] -> [a]
,它可以执行“无需映射就过滤掉Nothing
s”,但是由于要映射为展开,T
构造函数mapMaybe
更加接近适合。
1 这种“我知道这里永远不会Nothing
,所以我不必处理”这种情况是非常丰富的错误源,容易被破坏当某些事情发生变化时,将来隐藏着不变性。因此,实际上利用Nothing
“不能”存在的知识来编写代码甚至不是一个好主意。您应该仍然处理这两种情况!
答案 2 :(得分:2)
模式匹配仅在函数的自变量中起作用,而不是函数体。您需要匹配的模式是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)
已被定义为Data.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}]