If expression in a cond - SyntaxError: unexpected token: ). The “do” at line 77 is missing terminator “end”

I created a small scripts that takes a lottery number of length x and loops until it finds a match. I created it just for learning purposes and out of curiosity of how many loops are needed to find a match.

At the moment it prints the number of loops to the terminal but I would prefer if it only printed every 5000 or so tries.

I put an if expression that checks the see if loop_num / 5000 ends in 0, in the cond for each non match but I get the following error:

"elixir elixirPlay.exs
** (SyntaxError) elixirPlay.exs:83: unexpected token: ). The “do” at line 77 is missing terminator “end”

HINT: it looks like the "do" on line 1 does not have a matching "end"

(elixir) lib/code.ex:813: Code.require_file/2

"

If I comment out the if it works again. Are if expressions allowed in conds? What’s the solution?

Any other other critiques on the code?

defmodule Play do

def random_numbered_balls num do
    (for _x <- 1..num, do: Enum.random 1..49) |> List.to_tuple
end


def loto(true), do: IO.puts "We have a match!"

def loto(num_of_balls), do: loto(random_numbered_balls(num_of_balls), num_of_balls, 0) 

def loto(static_balls_list, num_of_balls, loop_num) do
    static_balls = static_balls_list
    changing_balls = random_numbered_balls(num_of_balls)
    cond do
        (static_balls == changing_balls) ->
            IO.inspect static_balls 
            IO.inspect changing_balls
            loto(true) 
        (static_balls != changing_balls) ->
            #if (String.ends_with?(to_string(loop_num / 5000)), "0")), do: IO.puts "#{loop_num} tries"
            IO.puts "#{loop_num} tries" #(temp) would prefer to print only ever 5000 tries but can't get the above to work
            loop_num = (loop_num + 1)
            loto(static_balls, num_of_balls, loop_num)
    end
end

end #module end


Play.loto(x)

if (String.ends_with?(to_string(loop_num / 5000)), "0"))

This has too many ).

It should also be spelled if (loop_num % 5000 == 0), partly because that’s much more efficient than converting to string and checking the last character but mostly because / in Elixir does not mean integer division:

4214 / 5000
# evaluates to
0.8428

Other general notes:

static_balls = static_balls_list

What’s the intent of this line?

(static_balls != changing_balls) ->

Parentheses are not required here.

loop_num = (loop_num + 1)

And they’re DEFINITELY not required here

I highly recommend learning about and using mix format - it helps remember all the “where do the parens go” rules.

3 Likes

Thank you for the help.

Well spotted, “static_balls = static_balls_list” is redundant. It’s was left over from when the code was different. I have now deleted it, and replaced all static_balls with static_balls_list.

I edited the if to (loop_num % 5000 == 0) and get the following error:

(SyntaxError) elixirPlay.exs:83: syntax error before: ‘)’
(elixir) lib/code.ex:813: Code.require_file/2

The full line is: if (loop_num % 5000 == 0), do: IO.puts “#{loop_num} tries”

Thanks for the other pointers and I’ll check out https://hexdocs.pm/mix/Mix.Tasks.Format.html#content

I now have the if expression working with ((rem loop_num, 5000) == 0)
Edit: or (rem loop_num, 5000) == 0
Maybe I should have been a lisper!

You can always switch to LFE :slight_smile:

1 Like

You can always switch to LFE :slight_smile:

Oh wow, never head of that!

Finished and tidied up.

def random_numbered_balls num do
    (for _x <- 1..num, do: Enum.random 1..49) |> List.to_tuple
end


def lotto(true), do: {:match_found}
def lotto(num_of_balls), do: lotto(random_numbered_balls(num_of_balls), num_of_balls, 0) 
def lotto(static_balls_list, num_of_balls, loop_num) do
    changing_balls = random_numbered_balls num_of_balls
    cond do
        (static_balls_list == changing_balls) ->
            IO.inspect static_balls_list
            IO.inspect changing_balls
            IO.puts "We have a match. It took #{loop_num} tries in total."
            lotto(true) 
        (static_balls_list != changing_balls) ->
            if (rem loop_num, 100000) == 0, do: IO.puts "#{loop_num} tries"
            loop_num = loop_num + 1
            lotto(static_balls_list, num_of_balls, loop_num)
    end
end
end #module end

Play.lotto(3)

Hello,

def lotto(static_balls_list, num_of_balls, loop_num) do
    cond do
        (static_balls_list == changing_balls) ->

        (static_balls_list != changing_balls) ->
            # if your code goes the condition before is always true
    end
end

you can simply do

def lotto(static_balls_list, num_of_balls, loop_num) do
    if static_balls_list == changing_balls do
    else
    end
end

also you return loto(true you can direclty return the result {:match_found}

You have 3 functions signatures for loto

def lotto(true), do: {:match_found}
def lotto(num_of_balls), do: lotto(random_numbered_balls(num_of_balls), num_of_balls, 0) 
def lotto(static_balls_list, num_of_balls, loop_num) do

that describres 3 differents behaviour.

I rewrite your code as I probably code it (just sharing way of think not judging)

defmodule Loto do
  def shuffle(num) do
    # Use a List is better than custom Tuple length
    for _x <- 1..num, do: :rand.uniform(49)
  end

  # start loto
  def start(num_of_balls) do
    win?(
      shuffle(num_of_balls),
      shuffle(num_of_balls)
    )
  end
  
  # This line just set the default value for the 3th parameter
  # and is know as a function signature that do nothing more ;)
  def win?(list_of_balls, other_list_of_balls, loop_num \\ 1)

  # if we provide 1st et 2nd is the same value basically you win
  def win?(balls_list, balls_list, loop_num) do
    IO.puts("We have a match. It took #{loop_num} tries in total.")
    :match_found
  end

  # otherwise try again
  def win?(_, balls_list, loop_num) do
    if rem(loop_num, 100_000) == 0, do: IO.puts("#{loop_num} tries")

    balls_list
    |> Enum.count()
    |> shuffle()
    |> win?(balls_list, loop_num + 1)
  end
end


Loto.start(1)

I think win?/3 could be improve not my best piece of code.

Also start / win? will always return :match_found so not a usefull return.

Hope it help :wink:

3 Likes

Thank you, very interesting. I’ll reread your message tomorrow, run it and reply :).

1 Like

Have just been playing with your code solution. I find it clean and elegant. On the one hand I find it depressing as I was really happy with what I wrote but on the other, I feel excited as I can see how clean code can be. With my dyslexia and ADD, I find it difficult to read/write and follow code. From your code I can see that it can be broken up into small sub problems that are easy to follow.

I’m going let some forgetting set in, then rewrite it in a week or so with this new mind set. I’m really enjoying this journey.

Just one question: What is a List better than a Tuple ? I started with a List but because I kept printing Chars from the code points I switched to Tuples. I find choosing the best collection to use still a little confusing.

A tuple has a fixed size while list can grow.

1 Like

With time you’ll start thinking different (some one already say that :thinking: )

In general term, you use tuple for a structured data that you know the size in compile time. In your case we can’t.

But why knowing the size is so important? It allows you to play easily with the data.

For example pattern matching become an elegant way to accomplish things. With list, you can use [tail | head] for matching data.

E.g:

[h|t] = [1,2,3]
# h -> 1
# y -> [2,3]

Doing this with tuple is little bit harder. The first way is : you now the size you can match data so you can do something like the code bellow

{a,b,c} = {1,2,3}

However, imagine you put 50 elements in the tuple and it become a nightmare.

Or you can use elem/2 But it’s not a pattern matching and it will not be useful in our case.

elem({1,2,3}, 1) 
2

I explain you that because the main thing about functional programming is thinking of the future. When you write a function your main goal is to provide a piece of code that could be use again and again without any modification. That’s why I had 3 little functions instead of one bigger. Each one does exactly one thing.

So here, I use a list because needs could evolve to : if there is rights numbers but in different order print « you were close » in the console. Doing this with list a pretty easy and the code will be elegant (It could be an great exercice btw).

And for charlists, you can take a look at Elixir lists interpreted as char lists - Stack Overflow

When I was young I was diagnosed with dyslexia. With time, code help me a lot. Keep in mind dyslexia is an advantage. Your brain work differently and it will give you the opportunity to think how to accomplish things differently.

Have a great day :wink:

3 Likes