Kết hợp các đoạn mã Haskell để có được bức tranh lớn hơn


12

Đây là mã mà tôi đã tìm thấy ở đâu đó nhưng muốn biết làm thế nào nó hoạt động:

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

Output: findIndices (== 0) [1,2,0,3,0]==[2,4] , nơi pred(==0)& xs[1,2,0,3,0]

Tôi sẽ chỉ ra một số hiểu biết của tôi:

    (zip [0..] xs)

Những gì dòng trên làm là đặt các chỉ số cho tất cả mọi thứ trong danh sách. Đối với đầu vào được đưa ra ở trên, nó sẽ trông như thế này : [(0,1),(1,2),(2,0),(3,3),(4,0)].

    (pred . snd)

Tôi thấy rằng điều này có nghĩa là một cái gì đó như pred (snd (x)). Câu hỏi của tôi là, xdanh sách được thực hiện từ zipdòng? Tôi nghiêng về phía có nhưng dự đoán của tôi là mỏng manh.

Tiếp theo, là sự hiểu biết của tôi về fstsnd. tôi biết điều đó

    fst(1,2) = 1 

    snd(1,2) = 2

Làm thế nào để hai lệnh này có ý nghĩa trong mã?

Sự hiểu biết của tôi filterlà nó trả về một danh sách các mục phù hợp với một điều kiện. Ví dụ,

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

sẽ cho [6,7,8,9,10]

Sự hiểu biết của tôi về bản đồ là nó áp dụng một chức năng cho mọi mục trong danh sách. Ví dụ,

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

sẽ cho [4,8,12,16,20]

Làm thế nào để làm việc này tổng thể? Tôi nghĩ rằng tôi đã toàn diện trong những gì tôi biết cho đến nay nhưng không thể đặt các mảnh lại với nhau. Ai có thể giúp tôi không?


7
Tôi chỉ muốn nói rằng đọc câu hỏi này là một niềm vui hiếm có. Chúng ta nhận được "làm thế quái nào mã này hoạt động?" câu hỏi thường xuyên, nhưng hiếm khi với mức độ giải thích này về những gì người hỏi làm và chưa hiểu. Điều đó làm cho nó thực sự thú vị để viết một câu trả lời tốt, nhắm mục tiêu về chính xác những khoảng trống bạn có.
Daniel Wagner

Cảm ơn Daniel! Tôi đã dành rất nhiều thời gian trong vấn đề này và đó là lý do tại sao, tôi có thể xác định chính xác những gì tôi cần giúp đỡ.
Shreeman Gautam

Tôi muốn thêm rằng câu trả lời @WillNess cũng hoạt động. Đó là cách dễ dàng hơn trong mắt và dễ hiểu.
Shreeman Gautam

Câu trả lời:


2

Trong Haskell chúng tôi muốn nói, hãy làm theo các loại . Thật vậy, các mảnh kết nối như thể bởi các dây đi từ loại này sang loại tương ứng:

(đầu tiên, thành phần chức năng là:

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

quy tắc suy luận kiểu thành phần chức năng là:

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

Hiện nay, )

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]

vì vậy, tổng thể,

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

Bạn đã hỏi, làm thế nào để những mảnh này khớp với nhau?

Đây là cách làm.


Với sự hiểu biết danh sách , chức năng của bạn được viết là

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

mà trong mã giả đọc:

"danh sách kết quả chứa icho mỗi (i,x)trong zip [0..] xsđó pred xgiữ" .

Nó thực hiện điều này bằng cách xoay n-long

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

vào

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

nơi [a | True][a][a | False][].


8

Tôi thấy rằng điều này có nghĩa là một cái gì đó như pred (snd (x)). Câu hỏi của tôi là, x danh sách được làm từ dòng zip? Tôi nghiêng về phía có nhưng dự đoán của tôi là mỏng manh.

Vâng pred . snd, có nghĩa là \x -> pred (snd x). Vì vậy, điều này về cơ bản xây dựng một chức năng ánh xạ một phần tử xtrên pred (snd x).

Điều này có nghĩa là biểu thức trông như sau:

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

xDo đó, đây là một tuple 2 được tạo bởi zip. Vì vậy, để biết nếu (0, 1), (1,2), (2, 0)vv được giữ lại trong kết quả, snd xsẽ mất phần tử thứ hai trong số này 2-tuples (vì vậy 1, 2, 0, vv), và kiểm tra xem predtrên tha yếu tố được thỏa mãn hay không. Nếu nó được thỏa mãn, nó sẽ giữ lại phần tử, nếu không phần tử đó (2-tuple) được lọc ra.

Vì vậy, nếu (== 0)predicate, thì filter (pred . snd) (zip [0..] xs)sẽ chứa 2-tuples [(2, 0), (4, 0)].

Nhưng bây giờ kết quả là một danh sách 2-tuples. Nếu chúng ta muốn các chỉ số, bằng cách nào đó chúng ta cần phải loại bỏ 2-tuple và phần tử thứ hai của 2-tuple này. Chúng tôi sử dụng fst :: (a, b) -> acho điều đó: điều này ánh xạ 2-tuple trên phần tử đầu tiên của nó. Vì vậy, cho một danh sách [(2, 0), (4, 0)], map fst [(2, 0), (4, 0)]sẽ trở lại [2, 4].


1
Này Willem, thật là một lời giải thích tuyệt vời! Tôi đã hiểu mã đầy đủ bây giờ. Cảm ơn ngài!
Shreeman Gautam
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.