[HN Gopher] Unifying fold left and fold right in Prolog
       ___________________________________________________________________
        
       Unifying fold left and fold right in Prolog
        
       Author : gopiandcode
       Score  : 61 points
       Date   : 2022-08-26 17:03 UTC (5 hours ago)
        
 (HTM) web link (gopiandcode.uk)
 (TXT) w3m dump (gopiandcode.uk)
        
       | galaxyLogic wrote:
       | Paper-based explanation of folding:
       | 
       | https://www.globalnerdy.com/2008/09/03/enumerating-enumerabl...
        
         | noneeeed wrote:
         | That's a lovely little demonstration.
         | 
         | The method name `inject` needs to be formally deprecated in
         | Ruby. It's fundamentally a simple method, but the name _really_
         | throws people off. Reduce isn't perfect, but it's a bit closer
         | to what's happening.
        
           | galaxyLogic wrote:
           | In Smalltalk it is called inject:into: which I think is quite
           | descriptive.
           | 
           | You "inject" (as in push, insert) elements of the recipient-
           | collection one by one INTO a 2-argument function, which
           | function gets replaced by a new version of itself after each
           | element has been "injected" into it.
           | 
           | In contrast I am always confused by names like "foldLeft".
           | Does it mean "fold elements starting FROM left", or "fold
           | elements TO left" ?
           | 
           | Here the Object-Oriented syntax of Smalltalk and Ruby has an
           | advantage: The name of the method is a command (-verb) to the
           | recipient, passing along arguments. The list to iterate over
           | is not one of the arguments, the list is the recipient of the
           | method-call.
           | 
           | Therefore the method-name does not need to say anything about
           | the recipient, and can thus focus on what should be done with
           | the arguments, and thus can can be more clear about that.
        
             | noneeeed wrote:
             | I certainly agree with you that `fold` is a terrible name
             | for it. That makes me think of some kind of halving action.
             | 
             | "inject:into" is definitely a bit better. It's amazing how
             | quite a small addition to a name can make a big difference.
             | I'm always keen on my team using longer method/variable
             | names when it can help with meaning, sometimes just a small
             | expansion can really help readability.
        
               | JadeNB wrote:
               | > I certainly agree with you that `fold` is a terrible
               | name for it. That makes me think of some kind of halving
               | action.
               | 
               | I think the poster expressed no opinion on `fold` itself,
               | only on the obviousness or un- of which way `foldl`
               | folds: that is, ignoring base conditions,
               | afold f z (x:xs) = f x (afold f z xs)
               | 
               | can be said to fold _from_ the left, whereas
               | bfold f z (x:xs) = bfold f (f z x) xs
               | 
               | can be said to fold _to_ the left. It happens that the
               | latter is what we call `foldl`, but I think one can 't
               | reasonably argue that a clean-room re-discovery of
               | folding--which would surely discover both implementations
               | --would be guaranteed to impose the same convention. (As
               | weak evidence for this, I note that I would be willing to
               | bet only a tiny sum of fake internet points that your
               | grandparent would agree on which of these _they_ meant by
               | "fold from the left", and which of these they meant by
               | "fold to the left".)
        
       | jfarmer wrote:
       | Here's a neat paper on fold by Graham Hutton: "A tutorial on the
       | universality and expressiveness of fold"
       | 
       | https://www.cs.nott.ac.uk/~pszgmh/fold.pdf
       | 
       | It gives a sufficient and necessary condition for when a function
       | can be written as a (right) fold.
       | 
       | It's not clear whether the author means to say foldl and foldr
       | are equivalent, or only that any foldl call which terminates can
       | be converted into a foldr call.
       | 
       | The latter is true, but the former is false.
       | 
       | For finite lists, every foldl call can be translated into a foldr
       | call that produces the same result (and vice versa).
       | 
       | Foldr still makes sense for infinite lists in a language w/ lazy
       | evaluation, but foldl will recurse forever.
        
         | gopiandcode wrote:
         | > It's not clear whether the author means to say foldl and
         | foldr are equivalent, or only that any foldl call which
         | terminates can be converted into a foldr call.
         | 
         | Oh, no, I wasn't trying to say that they were equivalent in
         | general - of course, fold right is the more general operator,
         | as you can implement fold left in terms of fold right. (As an
         | OCaml programmer, I'm used to assuming that all my lists are
         | finite[1]).
         | 
         | The interesting part that I wanted to highlight was the fact
         | that when you express fold as a declarative relation, it is
         | possible to obtain both fold left and fold right essentially
         | for free. Maybe this is an obvious fact for Prolog
         | practitioners, but as a functional programmer this was a
         | somewhat surprising discovery for me.
         | 
         | > Here's a neat paper on fold by Graham Hutton: "A tutorial on
         | the universality and expressiveness of fold"
         | 
         | > https://www.cs.nott.ac.uk/~pszgmh/fold.pdf
         | 
         | Oh, nice! Thanks for the pointer, that's a great paper!
         | 
         | [1] Although technically it is possible to represent certain
         | restricted classes of infinite lists in OCaml:
         | https://v2.ocaml.org/manual/letrecvalues.html
        
           | mkeoliya wrote:
           | > of course, fold right is the more general operator, as you
           | can implement fold left in terms of fold right.
           | 
           | The other way works too: fold right can be implemented in
           | terms of fold left. Here's an approach using continuations in
           | OCaml:                 let fold_right f z xs =
           | (List.fold_left (fun kont x -> (fun y -> kont (f x y)))
           | Fun.id xs) z;;
        
         | rraval wrote:
         | Hah, you beat me to this by a minute. I guess I'm not the only
         | one that looks back on this paper with fondness.
        
           | 082349872349872 wrote:
           | After you have a right fold and a left fold (both of which
           | fold elemental values one by one into a bulk accumulation),
           | might as well pretend we've got access to a bit more working
           | memory than in the days of Unit Record Equipment, and write
           | an associative "bottom up" fold, that first combines pairs of
           | elemental values, then combines pairs of those combinations,
           | etc., terminating with a single bulk result.
           | 
           | cf http://xahlee.info/comp/i/ICFPAugust2009Steele.pdf
        
       | rraval wrote:
       | Related: Graham Hutton's classic paper: a tutorial on the
       | universality and expressiveness of fold
       | 
       | [PDF]: https://www.cs.nott.ac.uk/~pszgmh/fold.pdf
       | 
       | Section 5.1 walks the reader through implementing foldl in terms
       | of foldr after laying down the ground work and gradually
       | introducing things one concept at a time.
       | 
       | For me, the eye-opening insight was using foldr to generate
       | intermediate functions as values, which is the sort of thing
       | "functional" programming does without thinking twice, but is mind
       | bending for someone coming from a more traditional procedural
       | language background.
        
       ___________________________________________________________________
       (page generated 2022-08-26 23:00 UTC)