I would disagree with "not expected in general." In general -- when a and b
are different types -- Elm's API design guidelines should set you up to
always expect a -> b -> b and never b -> a -> b. If the definition of foldl
were changed to take the latter, it would be the only exception to this
expectation.

On Fri, Dec 9, 2016 at 7:03 AM, Kasey Speakman <[email protected]> wrote:

> Ok, correction
>
> List.foldl (-) 0 [1, 2, 3]
> -- returns 2
> -- expands to 3 - (2 - (1 - 0)) = 2
>
> During my testing last night, I had a typo (foldr instead of foldl) when I
> was testing the expansions. That was the center-building behavior.
>
> Using the form a -> b -> b is right-building regardless of the order the
> list is traversed. Traversing from head to tail is equivalent to reversing
> the list and building right. This is obviously broken for left-associative
> only operations and not expected in general.
>
> On Friday, December 9, 2016 at 8:44:25 AM UTC-6, Kasey Speakman wrote:
>>
>> Sorry, that last bit was an example of what happens in Elm when folding
>> with string concat (++). That's unexpected behavior from a left fold.
>>
>> List.foldl (++) "" ["The ", "quick ", "brown "]  -- returns "brown quick
>> The "
>>
>> On Friday, December 9, 2016 at 8:26:17 AM UTC-6, Kasey Speakman wrote:
>>>
>>> You're confusing pipe's syntax and infix. Pipe is defined like this:
>>>
>>> (|>) x f = f x
>>>
>>> And used like this
>>>
>>> x |> f == f x
>>>
>>> So pipe has an inherent flip because it is used to chain otherwise
>>> right-building statements.
>>>
>>> e.g.
>>>
>>> List.sum (List.filter isOdd [1, 2, 3])
>>>
>>> vs
>>>
>>> [1, 2, 3]
>>> |> List.filter isOdd
>>> |> List.sum
>>>
>>> Pipe is inherently right-building, so operations like subtract or string
>>> concatenation are not suitable for it since they are only left associative.
>>>
>>> List.foldl (++) "" ["The ", "quick ", "brown "]  -- returns "brown quick
>>> The "
>>>
>>> On Friday, December 9, 2016 at 1:05:56 AM UTC-6, Aaron VonderHaar wrote:
>>>>
>>>> What's confusing here is how currying works with infix operators.  It's
>>>> idiomatic in Elm to have your accumulator be the last argument, and, for
>>>> instance, if you were writing your own data type, you would want to write
>>>> your functions so that they can be chained together easily:
>>>>
>>>>     myMatrix
>>>>         |> scale 2
>>>>         |> subtract 5
>>>>         |> subtractMatrix myOtherMatrix
>>>>         |> normalize
>>>>
>>>>
>>>> But as an infix operator (-) is not able to follow that convention;
>>>>
>>>>     5
>>>>         |> (-) 3
>>>>         |> (-) 1
>>>>
>>>> is confusingly equivalent to `(1 - (3 - 5))` rather than to `5 - 3 - 1`
>>>>
>>>>
>>>> If you had a function `subtract` such that
>>>>
>>>>     5 |> subtract 3 |> subtract 1 == (5 - 3 - 1)
>>>>
>>>> then you could use that function with fold as you intend
>>>>
>>>>     List.foldl subtract 0 [1, 2, 3, 4]  ==  -10
>>>>
>>>> You can achieve the same result with
>>>>
>>>>     List.foldl (flip (-)) 0 [1, 2, 3, 4]  ==  -10
>>>>
>>>>
>>>> Another way to put it is, in Elm, folds expand in the following way:
>>>>
>>>>     List.foldl f x [b, c, d]  ==  x |> f b |> f c |> f d
>>>>     List.foldr f x [b, c, d]  ==  f b <| f c <| f d <| x
>>>>
>>>>
>>>> On Thu, Dec 8, 2016 at 7:50 PM, Kasey Speakman <[email protected]>
>>>> wrote:
>>>>
>>>>> (deleted and corrected original post with proper expansion of Elm's
>>>>> foldl)
>>>>>
>>>>> I know this is a really old thread, but I ran into this precise
>>>>> question and thought I would add a perspective.
>>>>>
>>>>> The form a -> b -> b is not left-building, regardless of the direction
>>>>> you are traversing the list.
>>>>>
>>>>> An example: Starting from zero, subtract the numbers 1, 2, and 3. The
>>>>> expected answer is -6.
>>>>>
>>>>> List.foldl (-) 0 [1, 2, 3]
>>>>> -> returns -6 in Haskell (well, actually tested in F# which uses same
>>>>> order as Haskell)
>>>>>     expands to: ((0 - 1) - 2) - 3 = -6
>>>>> -> returns 2 in Elm
>>>>>     expands to: 3 - ((1 - 0) - 2)
>>>>>
>>>>> Elm's expansion is wonky for this. It appears to be center-building:
>>>>>     List.foldl (-) 0 [1] -- returns 1, expands 1 - 0
>>>>>     List.foldl (-) 0 [1, 2] -- returns -1, expands (1 - 0) - 2
>>>>>     List.foldl (-) 0 [1, 2, 3] -- returns 2, expands 3 - ((1 - 0) - 2)
>>>>>     List.foldl (-) 0 [1, 2, 3, 4] -- returns -2, expands (3 - ((1 - 0)
>>>>> - 2)) - 4
>>>>>
>>>>> When a and b are the same type it will only return the correct answer
>>>>> if the fold operation is also commutative or if flip is used to
>>>>> correct the ordering. When a and b are not the same type, the compiler 
>>>>> will
>>>>> provide an error for wrong ordering of course.
>>>>>
>>>>> I started out on the side that a -> b -> b was correct as that feels
>>>>> like proper "reduction" or chainable syntax. But after exploring it, it is
>>>>> clearly not left-building. Makes sense when you consider this form is used
>>>>> with pipe to convert right-building operations into left-reading code. 
>>>>> e.g. a
>>>>> |> f |> g |> h instead of h (g (f a))
>>>>>
>>>>> On Tuesday, July 16, 2013 at 6:13:01 AM UTC-5, Evan wrote:
>>>>>>
>>>>>> Gotcha, I definitely see the reasoning :)
>>>>>>
>>>>>>
>>>>>> On Tue, Jul 16, 2013 at 12:54 PM, Balazs Komuves <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>> I was not engaging in debate, religious or not (though I tend to
>>>>>>> have very strong opinions about these questions). I was explaining why I
>>>>>>> think Haskell uses the order it uses (because it is distinguished from a
>>>>>>> mathematical viewpoint). Of course you are not required to follow that
>>>>>>> convention, I was just pointing out that it is not simply an ad-hoc 
>>>>>>> choice.
>>>>>>>
>>>>>>> Balazs
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Jul 16, 2013 at 12:21 PM, Evan Czaplicki <[email protected]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> I think this might be a religious debate on some level. My first
>>>>>>>> functional languages were Scheme
>>>>>>>> <http://docs.racket-lang.org/reference/pairs.html#(def._((lib._racket/private/list..rkt)._foldl))>
>>>>>>>> and Standard ML <http://www.standardml.org/Basis/list.html>. The
>>>>>>>> libraries I just linked both use the same argument order for foldl and
>>>>>>>> foldr as in Elm. I was raised a certain way and it just stuck in my 
>>>>>>>> mind. I
>>>>>>>> suspect that everyone prefers the order they learned first because it
>>>>>>>> matches their mental model.
>>>>>>>>
>>>>>>>> I wrote up a bunch of "reasoning", but really, I am just engaging
>>>>>>>> in the religious debate. I'd feel bad deleting it all though, so here 
>>>>>>>> is
>>>>>>>> some of it:
>>>>>>>>
>>>>>>>> OCaml's list library
>>>>>>>> <http://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html> does
>>>>>>>> it the way you suggest. I find this order offensive on some level.
>>>>>>>>
>>>>>>>> The big questions for "physical" argument order are as follows:
>>>>>>>>
>>>>>>>>    - What is the type of `fold` or `reduce`? When you fold an
>>>>>>>>    unordered thing, is it from the right or the left?
>>>>>>>>    - What is the type of `foldp`? Which way does time go? Is this
>>>>>>>>    cultural?
>>>>>>>>
>>>>>>>> I don't find these questions particularly useful, and I don't think
>>>>>>>> programmers should have to wonder about them to use fold and foldp.
>>>>>>>>
>>>>>>>> At the end of the day, I chose the types on purpose. I find them
>>>>>>>> easier to use, easier to teach, easier to understand. I want to keep 
>>>>>>>> them
>>>>>>>> this way.
>>>>>>>>
>>>>>>>>
>>>>>>>> On Tue, Jul 16, 2013 at 10:40 AM, Balazs Komuves <[email protected]
>>>>>>>> > wrote:
>>>>>>>>
>>>>>>>>>
>>>>>>>>> The Haskell version of the foldl is the "right one" in the
>>>>>>>>> following sense:
>>>>>>>>>
>>>>>>>>> foldl makes sense in general for left-associative operators, and
>>>>>>>>> foldr makes sense for right-associative operators.
>>>>>>>>> Left-associative operators must have the type (a -> b -> a), while
>>>>>>>>> right-associative operators must have type (a -> b -> b).
>>>>>>>>>
>>>>>>>>> I think the fact that you cannot change a foldr to foldl without
>>>>>>>>> changing the types is actually an advantage: it forces you to think 
>>>>>>>>> about
>>>>>>>>> which version is the "proper" one, and you cannot accidentally do the 
>>>>>>>>> wrong
>>>>>>>>> one. Of course sometimes it can be inconvenient.
>>>>>>>>>
>>>>>>>>> What I somewhat dislike in the Haskell version of foldr (not
>>>>>>>>> foldl), is that while
>>>>>>>>>
>>>>>>>>> (foldl . foldl . foldl) etc makes sense, (foldr . foldr) does not;
>>>>>>>>> for that to work you would have to flip the last two arguments:
>>>>>>>>>
>>>>>>>>> myfoldr :: (a -> b -> b) -> ([a] -> b -> b)
>>>>>>>>> myfoldr f xs y = foldr f y xs
>>>>>>>>>
>>>>>>>>> But the practicality of this change is debatable, I guess.
>>>>>>>>>
>>>>>>>>> Balazs
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Wed, Jul 10, 2013 at 4:38 PM, Evan Czaplicki <[email protected]>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>> It's partly about composability (i.e. the data structure should
>>>>>>>>>> be last).
>>>>>>>>>>
>>>>>>>>>> It is also about reuse. In Elm it is valid to say:
>>>>>>>>>>
>>>>>>>>>> foldl (::) []
>>>>>>>>>> foldr (::) []
>>>>>>>>>>
>>>>>>>>>> If I want to change the order of my traversal, I should not
>>>>>>>>>> *also* need to change the definition of mildly related functions
>>>>>>>>>> or start using flip on things.
>>>>>>>>>>
>>>>>>>>>> Finally, once you know that the accumulator is always the second
>>>>>>>>>> argument, you do not have to look at docs anymore. Even now I forget 
>>>>>>>>>> the
>>>>>>>>>> order of arguments in Haskell's folds and need to look it up.
>>>>>>>>>>
>>>>>>>>>> I first learned this way from Standard ML
>>>>>>>>>> <http://www.standardml.org/Basis/list.html>, and it is my
>>>>>>>>>> favorite by far.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Wed, Jul 10, 2013 at 4:12 PM, Tim hobbs <[email protected]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>> Well, elm's ordering is more useful.  For example, I recently
>>>>>>>>>>> had a case where I wrote:
>>>>>>>>>>>
>>>>>>>>>>> let
>>>>>>>>>>>   irrelivantFuncitonName fold = fold blabla default list
>>>>>>>>>>> in
>>>>>>>>>>>  irrelivantFunctionName foldl + irrelivantFuncitonName foldr
>>>>>>>>>>>
>>>>>>>>>>> In Haskell, the same example ends up being
>>>>>>>>>>>
>>>>>>>>>>> let
>>>>>>>>>>>   irrelivantFuncitonName fold = fold blabla default list
>>>>>>>>>>> in
>>>>>>>>>>>  irrelivantFunctionName foldl + irrelivantFuncitonName (\f d l->
>>>>>>>>>>> foldr (\a b->f b a) d l)
>>>>>>>>>>>
>>>>>>>>>>> Tim
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Wednesday, July 10, 2013 4:03:23 PM UTC+2, Zsombor Nagy wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi!
>>>>>>>>>>>>
>>>>>>>>>>>> I wonder why is the foldl in Elm and in Haskell calling the
>>>>>>>>>>>> binary operator with arguments in a different order?
>>>>>>>>>>>>
>>>>>>>>>>>> foldl (\t acc -> acc + 1) 0 [1, 1, 1, 1, 1, 1]
>>>>>>>>>>>> haskell: 2
>>>>>>>>>>>> Elm: 6
>>>>>>>>>>>>
>>>>>>>>>>>> For me the haskell way seems more straightforward, but maybe
>>>>>>>>>>>> that "optimal composibility guideline" makes this turn around?
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> zs
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>>> Google Groups "Elm Discuss" group.
>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from
>>>>>>>>>>> it, send an email to [email protected].
>>>>>>>>>>> For more options, visit https://groups.google.com/groups/opt_out
>>>>>>>>>>> .
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>> Google Groups "Elm Discuss" group.
>>>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>>>> send an email to [email protected].
>>>>>>>>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>>> Groups "Elm Discuss" group.
>>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>>> send an email to [email protected].
>>>>>>>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>> Groups "Elm Discuss" group.
>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>> send an email to [email protected].
>>>>>>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> You received this message because you are subscribed to the Google
>>>>>>> Groups "Elm Discuss" group.
>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>> send an email to [email protected].
>>>>>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "Elm Discuss" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>>> an email to [email protected].
>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>
>>>>
>>>> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to