【问题标题】:Generic type of (map . filter)(map .filter)的通用类型
【发布时间】:2021-12-19 09:29:25
【问题描述】:

我不明白为什么map . filter 泛型类型是map . filter :: (a -> Bool) -> [[a]] -> [[a]]

我知道地图和过滤器类型是map :: (a -> b) -> [a] -> [b]filter :: (a -> Bool) -> [a] -> [a]。还有(.) :: (b -> c) -> (a -> b) -> a -> c

所以我的猜测是 a = (a -> Bool) -> [a], b = [a] 并且由于 filter 的输出不是函数,我认为 map . filter 会返回一个函数,该函数期望函数 (a -> b)

我不明白为什么该类型是a 的列表列表,因为mapfilter 都没有列表列表。我也不明白为什么它只适用于一个功能,因为两者都需要一个。

有人能解释一下它是如何工作的吗?

【问题讨论】:

  • 请注意,a -> b -> ca -> (b -> c) 的含义相同。(a -> b) -> c 是完全不同的类型 - 但您的 cmets 暗示您认为它是等价的。

标签: haskell filter types type-inference map-function


【解决方案1】:

(.)的类型,

(.) :: (b -> c) -> (a -> b) -> a -> c
 --       f     .     g     :: a -> c    when g :: a->b, f :: b->c

意思是

    g :: a -> b
f     ::      t -> c
--------------------   , b ~ t
f . g :: a ->      c

然后按照同样的模式,我们马上就得到了

      filter :: (a->Bool) -> ([a] -> [a])
map          ::              ( s  ->  t ) -> [ s ] -> [ t ]
----------------------------------------------------------- 
                           s ~ [a]   t ~ [a]
----------------------------------------------------------- 
map . filter :: (a->Bool) ->                 [[a]] -> [[a]]

这也是有道理的。 (map . filter) p = map (filter p),所以这个mapfilter p 应用于列表的每个元素(就像maps 一样)。

p :: a -> Bool,然后是filter p :: [a] -> [a]

由于此函数应用于列表的每个元素,这意味着该列表的每个元素都具有[a] 类型,并转换为另一个[a]

因此整个列表是[[a]],转换后的结果也是[[a]]

【讨论】:

    【解决方案2】:

    首先,让我们为函数中的类型使用不同的字母。这样我们就不会感到困惑了。

    map :: (a -> b) -> [a] -> [b]
    filter :: (c -> Bool) -> [c] -> [c]
    (.) :: (e -> f) -> (d -> e) -> d -> f
    

    所以现在我们考虑map . filter。进行替换我们得到以下结果(~ 用于类型相等):

    d ~ (c -> Bool)
    e ~ ([c] -> [c])   -- Result of 'filter'
    e ~ (a -> b)       -- Argument of 'map'
    f ~ ([a] -> [b])
    

    请注意我们如何获得e 的两种类型。通过替换,

    a ~ b ~ [c]
    

    所以

    f ~ ([[c]] -> [[c])
    

    因此我们可以在(.)的定义中替换df并得到

    (c -> Bool) -> [[c]] -> [[c]]
    

    GHCi 告诉我们的是什么。

    这个函数实际上所做的是将过滤器应用于每个子列表; map 采用的函数参数是过滤器。所以在 GHCi 中,

    Prelude> import Data.Char
    Prelude Data.Char> (map.filter) isDigit ["foo123", "456bar"]
    ["123","456"]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-27
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多