Поєднання фрагментів коду 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,0), (3,3), (4,0)]

    (pred . snd)

Я виявив, що це означає щось на кшталт pred (snd (x)). Моє запитання, чи x список складається із zip line? Я схиляюся до так, але я здогадуюсь надуманий.

Далі - моє розуміння fst та snd. я знаю це

    fst(1,2) = 1 

і

    snd(1,2) = 2

Як ці 2 команди мають сенс у коді?

Я розумію, що фільтр полягає в тому, що він повертає список елементів, які відповідають умові. Наприклад,

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

дасть [6,7,8,9,10]

Я розумію карту, що вона застосовує функцію до кожного елемента списку. Наприклад,

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

дасть [4,8,12,16,20]

Як це працює в цілому? Я думаю, що я був всеосяжним у тому, що знаю досі, але не можу цілком скласти шматки. Хтось може мені допомогти?


7
Я хотів би сказати, що читання цього питання було рідким задоволенням. Ми отримуємо "як чорт працює цей код?" запитує часто, але рідко з цим рівнем пояснення того, що запитувач робить, а ще не розуміє. Це робить насправді цікавим написання хорошої цілеспрямованої відповіді про саме ваші прогалини.
Даніель Вагнер

Дякую, Даніеле! Я витратив багато часу на цю проблему, і саме тому я міг точно визначити, в чому мені потрібна допомога.
Шреман Гаутам

Хочу додати, що відповідь @WillNess також працює. Це набагато легше для очей і легко зрозуміти.
Шріман Гаутам

Відповіді:


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-довго

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

в

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

де [a | True]є [a]і [a | False]є [].


Ви отримали свій голос. Дякую!
Шріман Гаутам

8

Я виявив, що це означає щось подібне pred (snd (x)). Моє запитання, чи x список складається із zip line? Я схиляюся до так, але я здогадуюсь надуманий.

Ну pred . snd, значить \x -> pred (snd x). Таким чином, це в основному будує функцію, яка відображає елемент xна pred (snd x).

Це означає, що вираз виглядає так:

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

Ось xтаким чином утворюється 2-кортеж zip. Тому для того , щоб знати , якщо (0, 1), (1,2), (2, 0)і т.д. зберігаються в результаті, snd xбуде приймати другий елемент з цих 2-кортежів (так 1, 2, 0і т.д.), і перевірити , якщо predна руховий елемент задовольняє чи ні. Якщо він задоволений, він збереже елемент, інакше цей елемент (2-х кортеж) відфільтрується.

Отже, якщо (== 0)це predікат, то 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
Гей Віллем, яке чудове пояснення! Зараз я зрозумів повний код. Дякую вам сер!
Шреман Гаутам
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.