การรวมส่วนของ Haskell Code เพื่อให้ได้ภาพที่ใหญ่ขึ้น


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 เป็นรายการที่ทำจากเส้นซิปหรือไม่ ฉันเอนไปทางใช่ แต่การคาดเดาของฉันนั้นบอบบาง

ต่อไปคือความเข้าใจของฉันของ 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
ฉันแค่อยากจะบอกว่าการอ่านคำถามนี้เป็นความสุขที่หายาก เราได้รับ "รหัสนี้ทำงานอย่างไรได้อย่างไร" คำถามบ่อย ๆ แต่ไม่ค่อยมีคำอธิบายในระดับนี้ว่าผู้ถามทำอะไรและไม่เข้าใจ นั่นทำให้สนุกกับการเขียนคำตอบที่ดีและตรงเป้าหมายเกี่ยวกับช่องว่างที่คุณมี
Daniel Wagner

ขอบคุณแดเนียล! ฉันใช้เวลามากในปัญหานี้และนั่นคือเหตุผลที่ฉันสามารถระบุสิ่งที่ฉันต้องการความช่วยเหลือ
Shreeman Gautam

ฉันต้องการเพิ่ม @WillNess คำตอบที่ได้ผลเช่นกัน เป็นวิธีที่ง่ายต่อสายตาและเข้าใจง่าย
Shreeman Gautam

คำตอบ:


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]

คุณถามแล้วชิ้นส่วนเหล่านี้เข้ากันได้อย่างไร

นี่คือวิธี


ด้วยcomprehensions รายการฟังก์ชั่นของคุณเขียนเป็น

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

ซึ่งใน pseudocode อ่าน:

"รายการผลมี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))กัน คำถามของฉันคือ x เป็นรายการที่ทำจากเส้นซิปหรือไม่ ฉันเอนไปทางใช่ แต่การคาดเดาของฉันนั้นบอบบาง

ดีหมายถึงpred . snd \x -> pred (snd x)ดังนั้นนี้โดยทั่วไปสร้างฟังก์ชั่นที่แมองค์ประกอบบนxpred (snd x)

นี่หมายความว่านิพจน์มีลักษณะดังนี้:

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

ที่นี่xจึงเป็น 2 tuple zipสร้างขึ้นโดย ดังนั้นเพื่อที่จะรู้ว่าถ้า(0, 1), (1,2), (2, 0)และอื่น ๆ จะถูกเก็บไว้ในผลที่ได้snd xจะนำองค์ประกอบที่สองของทั้ง 2 tuples (ดังนั้น1, 2, 0ฯลฯ ) และตรวจสอบว่าpredในองค์ประกอบ tha เป็นที่พอใจหรือไม่ หากเป็นที่พอใจก็จะเก็บองค์ประกอบมิฉะนั้นองค์ประกอบ (2-tuple) จะถูกกรองออก

ดังนั้นถ้า(== 0)เป็นpredicate แล้วfilter (pred . snd) (zip [0..] xs)จะมี [(2, 0), (4, 0)]2

แต่ตอนนี้ผลที่ได้คือรายการของ 2-tuples ถ้าเราต้องการดัชนีเราต้องกำจัดทูเปิลออกและองค์ประกอบที่สองของทูเปิลเหล่านี้ เราใช้fst :: (a, b) -> aสำหรับสิ่งนั้น: นี่แมป 2 ทูเปิลกับองค์ประกอบแรก ดังนั้นสำหรับรายการ[(2, 0), (4, 0)], จะกลับมาmap fst [(2, 0), (4, 0)][2, 4]


1
เฮ้วิลเล็มเป็นคำอธิบายที่ดีมาก! ตอนนี้ฉันเข้าใจรหัสเต็มแล้ว ขอบคุณมาก!
Shreeman Gautam
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.