结合Haskell代码片段以获得更大的画面


12

这是我在某处遇到的代码,但想知道它是如何工作的:

    findIndices :: (a -> Bool) -> [a] -> [Int]
    findIndices _ [] = []
    findIndices pred xs = map fst (filter (pred . snd) (zip [0..] xs))

输出:findIndices(== 0)[1,2,0,3,0] == [2,4],其中pred是(== 0)&xs是[1,2,0,3,0]

我将展示一些理解:

    (zip [0..] xs)

上一行所做的是将索引放入列表中的所有内容。对于上面给出的输入,它看起来像这样:[(0,1),(1,2,2,(2,0),(3,3),(4,0)]

    (pred . snd)

我发现这意味着像pred(snd(x))。我的问题是,列表是否由邮编组成?我倾向于是,但是我的猜测很脆弱。

接下来,是我对fst和snd的理解。我知道

    fst(1,2) = 1 

    snd(1,2) = 2

这两个命令在代码中如何有意义?

我对过滤器的理解是,它返回符合条件的项目列表。例如,

    listBiggerThen5 = filter (>5) [1,2,3,4,5,6,7,8,9,10]

会给[6,7,8,9,10]

我对map的理解是,它将map应用于列表中的每个项目。例如,

    times4 :: Int -> Int
    times4 x = x * 4
    listTimes4 = map times4 [1,2,3,4,5]

会给[4,8,12,16,20]

整体如何运作?我想到目前为止,我对自己所了解的内容已经很全面了,但是还不能完全整合。有人可以帮我吗?


7
我只想说读这个问题是一种难得的乐趣。我们得到“此代码如何工作?” 经常提出问题,但很少对询问者做什么和不了解的程度进行这种解释。这样就可以针对您之间的差距写出一个有针对性的好答案,这真的很有趣。
Daniel Wagner

谢谢丹尼尔!我在这个问题上花了很多时间,这就是为什么我可以指出需要帮助的地方。
Shreeman Gautam,

我想补充一点,@WillNess答案也可以。它在眼睛上更容易理解。
Shreeman Gautam

Answers:


2

在Haskell中,我们喜欢说,遵循类型。实际上,各部分之间的连接就像通过电线从类型到相应类型的连接一样:

(首先,功能组成为:

   (f >>> g) x  =  (g . f) x  =        g (f x)
   (f >>> g)    =  (g . f)    =  \x -> g (f x)

功能组成类型的推断规则为:

    f        :: a -> b                   --      x  :: a
          g  ::      b -> c              --    f x  :: b
   -------------------------             -- g (f x) :: c
    f >>> g  :: a ->      c
    g  .  f  :: a ->      c

现在,)

findIndices :: (b -> Bool) -> [b] -> [Int]
findIndices pred  = \xs -> map fst ( filter (pred . snd) ( zip [0..] xs ))
                  =        map fst . filter (pred . snd) . zip [0..]
                  =  zip [0..]  >>>  filter (snd >>> pred)  >>>  map fst
---------------------------------------------------------------------------
zip :: [a] ->          [b]        ->        [(a,  b)]
zip  [0..] ::          [b]        ->        [(Int,b)]
---------------------------------------------------------------------------
        snd           :: (a,b) -> b
                pred  ::          b -> Bool
       ------------------------------------
       (snd >>> pred) :: (a,b)      -> Bool
---------------------------------------------------------------------------
filter ::               (t          -> Bool) -> [t]   -> [t]
filter (snd >>> pred) ::                      [(a,b)] -> [(a,b)]
filter (snd >>> pred) ::                    [(Int,b)] -> [(Int,b)]
---------------------------------------------------------------------------
    fst ::                                   (a,   b) -> a
map     ::                                  (t        -> s) -> [t] -> [s]
map fst ::                                                 [(a,b)] -> [a]
map fst ::                                               [(Int,b)] -> [Int]

因此,总体而言,

zip  [0..] ::          [b]        ->        [(Int,b)]
filter (snd >>> pred) ::                    [(Int,b)] -> [(Int,b)]
map fst ::                                               [(Int,b)] -> [Int]
---------------------------------------------------------------------------
findIndices pred ::    [b] ->                                         [Int]

您问过,这些零件如何组合在一起?

就是这样


通过列表推导,您的函数写为

findIndices pred xs = [ i | (i,x) <- zip [0..] xs, pred x ]

用伪代码读取的内容是:

“结果列表中包含i了每个(i,x)zip [0..] xs这样pred x持有”

它通过将n-long 转到

xs = [a,b,...,z] = [a] ++ [b] ++ ... ++ [z]

进入

  [0 | pred a] ++ [1 | pred b] ++ ... ++ [n-1 | pred z]

这里[a | True][a][a | False][]


你有你的投票人。谢谢!
Shreeman Gautam

8

我发现这意味着类似pred (snd (x))。我的问题是,列表是否由邮编组成?我倾向于是,但是我的猜测很脆弱。

好吧pred . snd,手段\x -> pred (snd x)。因此,这基本上构建了一个元素映射的功能xpred (snd x)

因此,这意味着表达式看起来像:

filter (\x -> pred (snd x)) (zip [0..] xs)

x因此,这是由生成的2元组zip。因此,为了知道是否(0, 1)(1,2)(2, 0)等被保留在结果,snd x将采取这些2元组(这样的第二元件120等),并检查pred塔元件上被满足或没有。如果满足,它将保留该元素,否则将滤除该元素(2元组)。

因此,如果(== 0)predicate,filter (pred . snd) (zip [0..] xs)则将包含2元组[(2, 0), (4, 0)]

但是现在结果是一个2元组的列表。如果我们需要索引,则需要以某种方式摆脱2元组以及这些2元组的第二个元素。我们fst :: (a, b) -> a为此使用:这在其第一个元素上映射了一个2元组。因此,对于列表[(2, 0), (4, 0)]map fst [(2, 0), (4, 0)]将返回[2, 4]


1
嘿,威廉姆,真是个绝妙的解释!我现在已经了解了完整的代码。谢谢你,先生!
Shreeman Gautam
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.