Ad
  • Custom User Avatar

    Nobody's going to change the specifications of an old kata.

  • Custom User Avatar

    I prefer the way it is, since I want to emphasize the type of the function. (IMO the naming is strange, since it doesn't have to be an operator.) ;)

  • Custom User Avatar

    Well, thanks for your work, I really appreciate it. I'm glad I could contribute to your interest in functional programming, which for me changed a lot.

  • Custom User Avatar

    You're absolutely right. It has been fixed.

  • Custom User Avatar

    I don't mind at all! I'll have a look at it.

  • Custom User Avatar

    The term foldr means that the applications of the function are nested to the right. What you thought of is probably foldl, where applications are nested to the left: f( ... f(f(f(z, x0), x1), x2) ... ,xn). foldl itself doesn't make much sense on infinite data, as the result depends on the last application of f, but there is no last element, hence it will never terminate. (That should also answer your second question.)

    Exactly, in that case you're basically nesting infite applications of +, where the right side is a recursive call. So it would probably blow your stack (in Java a StackOverflow exception is thrown), but even if you had an infinite stack, it would not stop.

    Haskell has lazy semantics built in, that takes out a lot of complexity, and once you start with Haskell you see how much boilerplate code Java needs.

  • Custom User Avatar

    I'm glad you enjoy it. The java version currently has some issues with test cases.

    To clear up the confusion have a look at https://en.wikipedia.org/wiki/Fold_(higher-order_function). It is basically a chain of infinite applications of f, as the stream has no end and the neutral element is never reached, none is needed: f(x0, f(x1, f(x2, ...)))

    • The type of foldrS is public <R> R foldrS(BiFunction<T, Thunk<R>, R> f). So with an element of the stream and a thunk of the remaining stream folded, f gives you a value of the accumulator type! Can you imagine why we need a thunk here?

    • The point is you never stop. As long as the structure you generate by folding contains lazy parts, that work will never be done unless specifically requested by evaluating the thunk. To give you an example let's implement a function that builds the running sum with foldrS:

        public static Stream<Integer> runningSum(Stream<Integer> s) {
            // The type of the function we pass to foldrS: BiFunction<Integer, Thunk<Stream<Integer>>, Stream<Integer>>
            return s.foldrS((Integer h, Thunk<Stream<Integer>> t) -> new Stream<Integer>(h, t.chain(r -> r.fmap(x -> x + h))));
        }
    

    Note however that this is not very efficient as thunks build up and we have to do all the additions again every time (number of additions is in O(n^2)), because we're not actually using the previous result. This is not possible with foldr. Although, we could implement it very efficiently with iterateS and a user-defined tuple type:

        public static Stream<Integer> runningSum(Stream<Integer> sArg) {
            return Stream.iterateS(new Tuple<Stream<Integer>, Integer>(sArg, 0), t -> new Tuple<Stream<Integer>, Integer>(t.first.next(), t.first.headS() + t.second)).fmap(t -> t.second);
        }
    

    Don't worry, you're on a good way. It's not easy to grasp at first, but once you understand it, it can open a whole new world. Java doesn't make it particularly easy to write functional code, as it is simply not made for that purpose, so this kata is somehow an abomination. ;)

  • Custom User Avatar

    Yes i know;-)... Too dense - you are right:-), it's because typing on tablet or smartphone, so i often compress input, reducing var names too (often a little bit quick and dirty at codewars - but it's just for fun;-)).

  • Custom User Avatar

    Any suggestion?