Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take-A-Number not enough information #1482

Closed
mallowmew opened this issue May 22, 2024 · 5 comments · Fixed by #1511
Closed

Take-A-Number not enough information #1482

mallowmew opened this issue May 22, 2024 · 5 comments · Fixed by #1511

Comments

@mallowmew
Copy link

mallowmew commented May 22, 2024

Take-A-Number is the first exercise in the PID and Processes concepts. I don't think Take-A-Number gives enough information to allow for success as a first introduction to these concepts.

Note: I have been working through each concept by doing the introductory exercise and then moving onto the next concepts - I'm saving the 'practice' exercises for when I know the whole toolkit.

  • The introduction to the concept / exercise does not show a good example of where actually to put the receive do ... end block, and neither does the Elixir documentation.
  • Even when your receive do ... end block is inside the function supplied to spawn, the examples in the introduction and the Elixir docs only show supplying an anonymous function fn as parameter.
  • 'Use recursion' won't just work with an anonymous function.
  • The syntax for passing a named function in Elixir is not obvious. Both syntaxes that I found can lead to a solution but I was stuck here for a long time on something that doesn't seem directly related to what the exercise is trying to teach.
  • Before you do Task 4 (Stop) you can't run the tests to see if you're getting closer to the solution.
@angelikatyborska
Copy link
Contributor

Hi! Thank you so much for the feedback 🙏

Re: receive/do

The introduction to the concept / exercise does not show a good example of where actually to put the receive do ... end block

The introduction describes where to put the receive do ... end block. It says:

It is a common pattern to implement a recursive function, for example named loop, that calls receive/1, does something with the message, and then calls itself to wait for more messages.

Re: passing a named function

The syntax for passing a named function in Elixir is not obvious.

You're absolutely right, we forgot to mention anywhere in the course how to pass a named function as an argument 😱 I'll create a PR to fix that.

Re: cannot test before task 4 implemented

Before you do Task 4 (Stop) you can't run the tests to see if you're getting closer to the solution.

Can you give me more details about that? How exactly did your partial solutions look like, and what was preventing you from running the tests? I find it possible to run tests on partial solutions for every step of the exercise. I'm attaching videos to demonstrate.

Screen.Recording.2024-05-25.at.13.57.46.mov
Screen.Recording.2024-05-25.at.13.58.27.mov
Screen.Recording.2024-05-25.at.13.59.04.mov

@mallowmew
Copy link
Author

Re: receive/do

The introduction to the concept / exercise does not show a good example of where actually to put the receive do ... end block

The introduction describes where to put the receive do ... end block. It says:

It is a common pattern to implement a recursive function, for example named loop, that calls receive/1, does something with the message, and then calls itself to wait for more messages.

I remember my first attempts at just getting something to happen went something like:

def start() do
    spawn(fn -> send(sender_pid, {:report_state, self()}) end)  # I don't remember exactly what I was trying here but it didn't work
    receive do 
      {:report_state, sender_pid} -> send(sender_pid, x)
    end
end

Because that's what it kind of looks like is happening in the Elixir docs - except now I know they're using the interactive interpreter and doing something different.

I was still thinking about the first step of just trying to see a message being passed. Implementing the recursive function seemed like the next step after that, so I just didn't understand where receive do ... went. For me there was a gap between what you had written and the syntax that actually translates to.

Seeing the syntax in a full context where it will simply return one message would have helped me a lot:

def start() do
    spawn(fn -> 
        receive do 
            {:hello, sender_pid} -> send(sender_pid, "world")
        end
   end)
end

Before you do Task 4 (Stop) you can't run the tests to see if you're getting closer to the solution.

Can you give me more details about that? How exactly did your partial solutions look like, and what was preventing you from running the tests? I find it possible to run tests on partial solutions for every step of the exercise. I'm attaching videos to demonstrate.

I was incorrect about this. My problem with tests not running was because of not knowing how to pass in a named function and just trying stuff.

I was probably doing something like this:

def start() do
    spawn(loop(0))
end

This runs in Exercism but times out without indicating why it was wrong.

@conradwt
Copy link

In general, this exercise would better serve individuals if we were also asked to create the client interface. For example, there would be functions like current_number, take_number, stop_machine, and so on.

@angelikatyborska
Copy link
Contributor

For me there was a gap between what you had written and the syntax that actually translates to.

There is this global Exercism guideline about writing concept introductions:

Code examples should only be used to introduce new syntax (students should not need to search the web for examples of syntax). In other cases provide descriptions or links instead of code. (source: building tracks / concepts)

Defining functions and recursive calls are not new syntax in the context of the Take-A-Number exercise so I'm not supposed to include code snippets for that. The goal of this guideline is: 1) keeping introductions short and relevant, and 2) preventing mindless copy-pasting and encouraging careful reading with understanding.

The syntax for passing a named function in Elixir is not obvious.

You're absolutely right, we forgot to mention anywhere in the course how to pass a named function as an argument 😱 I'll create a PR to fix that.

I just realized that this exercise doesn't need passing a named function as an argument at all 🙈 I opened a PR that reverts those changes, slightly redefines the first two tasks of the exercise and adds more hints that should lead people to write this code, which is the exemplar solution:

  def start() do
    spawn(fn -> loop(0) end)
  end

Sorry for the late response. I've been struggling to prioritize open source work lately.

I hope the changes in #1511 are enough to address this problem. if not, I'm always open to more suggestions.

@mallowmew
Copy link
Author

I appreciate the need not to just give the answer in the exercise text. I think the changes in #1511 help a lot. Seeing an example of either way of putting a callback into spawn() properly would have been enough for me to reach the solution, so the PR changes defintely make the exercise do-able.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants