Search code examples
haskellpolymorphism

Foldln in haskell


Is it possible to write in haskell something similar to fold functions on many lists. Here is example for such function in Racket

#lang racket
(define (fold-left f i as . bss)
  (if (or (null? as)
          (ormap null? bss))
      i
      (apply fold-left
             f
             (apply f i (car as) (map car bss))
             (cdr as)
             (map cdr bss))))
 
(fold-left + 0 (list 1 2 3 4) (list 5 6 7 8))
(fold-left + 0 (list 1 2 3) (list 2 3 4) (list 3 4 5) (list 4 5 6))
(fold-left (λ (i v n s) (string-append i (vector-ref v n) s))
           ""
           (list (vector "A cat" "A dog" "A mouse")
                 (vector "tuna" "steak" "cheese"))
           (list 0 2)
           (list " does not eat " "."))

The example uses of fold-left evaluate to 36, 42, and "A cat does not eat cheese.". It seems to me not yet, but perhaps there is some trick that I haven’t thought of?


Solution

  • There's no direct equivalent because that would require creating list with (dynamically) heterogenous types. However, you can still pretty much achieve the same result using other operations in Haskell:

    (fold-left + 0 (list 1 2 3 4) (list 5 6 7 8))
    

    Would be sum $ zipWith (+) [1,2,3,4] [5, 6, 7, 8]

    (fold-left (λ (i v n s) (string-append i (vector-ref v n) s))
               ""
               (list (vector "A cat" "A dog" "A mouse")
                     (vector "tuna" "steak" "cheese"))
               (list 0 2)
               (list " does not eat " "."))
    

    Would be

    concat $ zipWith3 (\v n s -> concat [v!!n, s])
      [ ["A cat", "A dog", "A mouse"]
      , ["tuna", "steak","cheese"]
      ]
      [0, 2]
      [" does not eat ", "."]
    

    zipWith3 can be extended to any arbitrary (but fixed, because static typing) number of lists with the Applicative instance of ZipList:

    zipWith<n> f l1 ... ln === f <$> ZipList l1 <*> ... <*> ZipList ln
    

    So basically, instead of stuffing everything inside one big fold that somehow 'knows' how deep to go, you'd just write out the folds explicitly.