1 kyu

Sloth

Description
Loading description...
Functional Programming
Fundamentals
  • Please sign in or sign up to leave a comment.
  • TheBlackBeans Avatar

    I have some trouble with this Kata. First of all, it's not clear at all what the tie function should do (or, really, any other function). It's relatively straightforward to "guess" what other functions should do from their signature, but tie's signature is not enough for me. I guess it should be something like "create a dummy thunk in a reference, pass it to the function given and store the result where the dummy thunk was, then return it" but I'm not sure. And, because I'm unsure about that, I'm a little bit confused about what I should do for the fibonacci one.

    Secondly, I don't understand how it is possible in OCaml to actually make tail "lazy enough" with the provided signature. That is, the tests require the head not to be evaluated if I only want to tail of the stream, but since both the head and the tail are in the same thunk, it's impossible to evaluate one without the other. I tried changing the signature of Stream to provide two thunks, but then it doesn't work because the constructor is used directly in the tests (which is strange since the module also provides an interface to create streams).

    Finally, I'm not sure about which order to use in the join function. Since there are several ways to do that, and that each provides a different stream in the end, it's not clear which one should be chosen.

    • TheBlackBeans Avatar

      After some more attempts, I have circumvented the tail issue, by realizing it was my join which was not lazy enough! And that's because, even though it was successfully type-checked, it didn't do what it was supposed to because there wasn't a clear explanation about that :| This kata could really benefit from being more precise.

    • Glinator Avatar

      I’ll try to answer some of your points without revealing too much of the solution. (Just in case I’ll split the answer so a spoiler flag will not hide everything).

    • Glinator Avatar
      • This kata is quite under specified, yeah. In case you (or anyone) want to know what a function is supposed to do, it’s likely to be equivalent to the homonymous Haskell function.
    • Glinator Avatar
      • About tie specificaly, it’s hard to wrap your head around how it works - at least that’s my experience. So sorry I can’t help.
    • Glinator Avatar
      • For fib_aux, let’s say it’s a bit like building a list recursively, but adding stuff to the tail side lazily in the future :
        (* With list syntax : *)
        (* Instead of *)
        new_thing :: already_built
        (* You do *)
        currently_built :: will_do_in_the_future
        
    • Glinator Avatar
      • tail and join, can (and should) be really lazy. After all it’s a ’a L.t (or a Stream of it), so no evaluation is needed right now.
    • Glinator Avatar
      • Modifying signatures in general will most likely stop anything from even compiling. (but refactoring modules is possible, as written in the solution setup).
    • Glinator Avatar
      • The order of the element doesn’t matter in join, you just need to have every element of the «  2D stream » in the output « 1D stream ». Trying to exhaust the first stream, then the second, etc … will not work because they are, well, infinite.
    • TheBlackBeans Avatar

      This kata is quite under specified, yeah. In case you (or anyone) want to know what a function is supposed to do, it’s likely to be equivalent to the homonymous Haskell function.

      Unfortunately, I know almost nothing about Haskell (if I'm currently 4 kyu in Haskell it's merely because I found Kata were you don't need to know how to code in Haskell to finish them).

      For fib_aux, let’s say it’s a bit like building a list recursively, but adding stuff to the tail side lazily in the future

      My problem about that is how do I reuse already built information. I mean, I don't even know where to put the initializatoin!

      tail and join, can (and should) be really lazy. After all it’s a ’a L.t (or a Stream of it), so no evaluation is needed right now.

      Modifying signatures in general will most likely stop anything from even compiling. (but refactoring modules is possible, as written in the solution setup).

      After some thoughs, I realized what I was supposed to do for these.

      The order of the element doesn’t matter in join, you just need to have every element of the « 2D stream » in the output « 1D stream ».

      Except it does :') I tested my solution and it [stack overlowed / exceeded the allowed runtime] because the order I chose made it so that you have to wait very long before you actually reach the first element of the n-th stream. But I guess that's easy to fix (just a bit sad that my unpractical solution is rejected). I realized after posting that it was not because a given order was enforced, but rather because mine was really bad.

      Thanks for the tips! I think the only thing I am still struggling with is the fibonacci one...

    • Glinator Avatar

      About Haskell, I'm a noob too. I was hinting at the documentation eg. zipWith.

      I don't even know where to put the initialization !

      That's the neat part : nowhere. (Well kinda, but no spoil).

      Finally about join : the order doesn't matter because it is not tested, but the tests still need to access some elements so they have to be at a reasonable position (something exponential would not be reasonable).

      Ps : does your version of join really go through all elements ? If that's not the case then the tests may take elements forever.

    • TheBlackBeans Avatar

      That's the neat part : nowhere. (Well kinda, but no spoil).

      Well, I have a working thing but I'm not sure it's what was expected. I'll look at the other solutions when I'm done with this kata.

      Ps : does your version of join really go through all elements ? If that's not the case then the tests may take elements forever.

      Currently, I am battling a bit with Haskell so my join function doesn't do much; but when it "worked", it indeed went through all elements, except that you would see 2^n elements of the first stream before seeing the first of the n-th stream, which is probably why it broke down (NB. when I click on Attempt, it successfully passes the first batch of tests for LazyThunk, but not for LazyOption, because it times out — so the implementation is correct, it's just too long)... Whatever, I guess I'll just change the order, even if that's a bit longer to code.

  • spode Avatar

    This comment has been hidden.

    • spode Avatar

      Oh I figured it out. It must happen in such an order that those coordinates can be reached within finite time.

      I'm leaving this comment here as a hint because the requirement is frustratingly uninformative.

      Question marked resolved by spode 3 years ago
  • Whaaale Avatar

    This comment has been hidden.

  • Opabinia Avatar

    The description is actually terrifying... Well, since I've seen your other kata, I've got a fair idea of how this one is going to go. 🦥

    One day, I'm going to click "Train" on this kata—one day!

  • Eigenwert Avatar

    This comment has been hidden.

  • dramforever Avatar

    I'm now so impressed by GHC optimizations...

  • dramforever Avatar

    This comment has been hidden.

  • Voile Avatar

    Approved!

    Praise the Marisa! > <

  • Axure Avatar

    This is so tough for me, and very enlightening. I think it's worth a 1kyu, at least no less than any other 1kyu kata lol.

  • Axure Avatar

    If I understand the join of stream correctly, it takes the diagnol infinite matrix generated by the stream of streams, like the one here:

    instance Monad Stream where
      return = repeat
      xs >>= f = join (fmap f xs)
        where
          join :: Stream (Stream a) -> Stream a
          join ~(Cons xs xss) = Cons (head xs) (join (map tail xss))
    

    so how could I encounter (2, 3) in the product of two S.gen (fun n -> 1 + n) (L.return 0)s?