Some beginner questions regarding the Nucleotide problem of exercism.io

I’ve read the Basics of elixirschool only, so I have some questions regarding the Nucleotide problem of exercism.io.

Please take a look at https://paste.ofcode.org/37ZCKNYPTJbpFwcVLdMYRan

1. What’s the purpose of @nucleotides under the `defmodule` declaration?
2. Why does that tag mention A, C, G, T preceded by a question mark?
3. What is wrong, or how to correct my counthelper implementation?
4. What is the best source where I can have a more detailed esplanation than in elixirschool (i.e.) with examples?
• Why does that tag mention A, C, G, T preceded by a question mark?

i.e.

• What is the best source where I can have a more detailed explanation than in elixirschool (i.e.) with examples?

The “best” varies from person to person. But I don’t think you can go wrong with

First pass:

``````# file: nucleotide_count.exs
defmodule NucleotideCount do

def counthelper(c, strand, nucleotide) do
[hd | tl] = strand
cond do
hd == nucleotide -> counthelper(c + 1, tl, nucleotide)
length(tl) != 0 -> counthelper(c, tl, nucleotide)        # 2.) Need (length tl) or length(tl)
true -> c
end
end

def count(strand, nucleotide) do
counthelper(0, strand, nucleotide)
end
end # 1.) added missing module "end"

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
``````

But still:

``````\$ elixir nucleotide_count.exs
** (MatchError) no match of right hand side value: []
nucleotide_count.exs:5: NucleotideCount.counthelper/3
nucleotide_count.exs:18: (file)
(elixir) lib/code.ex:677: Code.require_file/2
\$
``````

i.e. `[hd | tl] = strand` the match fails when the list is empty - the code never gets to `length(tl) != 0`

quick fix: Pattern Matching

``````# file: nucleotide_count.exs
defmodule NucleotideCount do

def counthelper(c, [], _) do
c # ran out of strand - return count
end
def counthelper(c, strand, nucleotide) do
[hd | tl] = strand
cond do
hd == nucleotide -> counthelper(c + 1, tl, nucleotide)
length(tl) != 0 -> counthelper(c, tl, nucleotide)
true -> c
end
end

def count(strand, nucleotide) do
counthelper(0, strand, nucleotide)
end
end

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
``````
``````\$ elixir nucleotide_count.exs
4
1
\$
``````

But we can do better …

``````# file: nucleotide_count.exs
defmodule NucleotideCount do

def counthelper(c, [], _),
do: c                                                        # ran out of strand - return count
def counthelper(c, [hd|tl], nucleotide) when hd == nucleotide, # 1. move pattern match to function head
do: counthelper(c + 1, tl, nucleotide)                       # 2. extend pattern with a guard
def counthelper(c, [_|tl], nucleotide),                        # 3. here we know "hd" isn't the "nucleotide"
do: counthelper(c, tl, nucleotide)                           # we don't care about the "hd" so we use "_" instead

def count(strand, nucleotide),
do: counthelper(0, strand, nucleotide)

end

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
``````

The whole thing may look a bit more familiar this way:

``````# file: nucleotide_count.exs
defmodule NucleotideCount do

def counthelper(c, strand, nucleotide) do
case strand do
[x|xs] when x == nucleotide ->
counthelper(c+1,xs,nucleotide)
[_|xs] ->
counthelper(c,xs,nucleotide)
_ ->
c
end
end

def count(strand, nucleotide),
do: counthelper(0, strand, nucleotide)

end

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
``````

And then there is

``````# file: nucleotide_count.exs
defmodule NucleotideCount do

def count(strand, nucleotide) do
n_accumulate = fn
x,c when x == nucleotide -> c + 1
_,c -> c
end
List.foldl(strand, 0, n_accumulate)
end

end

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
``````

Defining Multiple Clauses In An Anonymous Function

8 Likes

Maybe You can replace cond with function head pattern matching.

``````defmodule NucleotideCount do
@nucleotides [?A, ?C, ?G, ?T]

def counthelper(c, [], _nucleotide), do: c
def counthelper(c, [head], nucleotide) when head == nucleotide, do: c + 1
def counthelper(c, [head], nucleotide) when head != nucleotide, do: c
def counthelper(c, [head | tail], nucleotide) when head == nucleotide do
counthelper(c + 1, tail, nucleotide)
end
def counthelper(c, [head | tail], nucleotide) when head != nucleotide do
counthelper(c, tail, nucleotide)
end

def count(strand, nucleotide) do
counthelper(0, strand, nucleotide)
end
end

iex(1)> IO.inspect(NucleotideCount.count('AATAA', ?A))
4
4
iex(2)> IO.inspect(NucleotideCount.count('AATAA', ?T))
1
1
``````

@nucleotides is not used, You might add some guard clause like this.

``````def counthelper(_c, [head | _tail], _nucleotide) when head not in @nucleotides, do: raise "error"
``````
1 Like

Excellent @peerreynders, excellent!
Thank you very much for your thorough answer!
I guess I should have read the official documents first as they’re more complete than elixirschool’s contents.

I wouldn’t like to abuse your patience, but there are several questions that arose:

1. It seems that every function parameter is a result of some pattern matching. Is this right? I searched but couldn’t find documentation on this. Maybe searched with wrong keywords. What I’ve found is something like this:

``````add_subscription(user, subscription)

def add_subscription(%User{subscription: nil} = user, subscription) do
#Add subscription here using user
end

def add_subscription(_user, _subscription) do
raise "This user already has a subscription"
end
``````

What’s this `%User{subscription: nil}` ? Is this a map? some shorthand for pattern matching?
I’ve also learnt from the source of the example https://medium.com/rebirth-delivery/how-to-use-elixir-pattern-matched-functions-arguments-a793733acc6d that there can be assignments in function headers… Elixir is powerful!

1. There’s two more different attempts to solve this problem, seems close but it’s not working. I’d like to know why:

`````` def count(strand, nucleotide) do
c = for l <- strand, l == nucleotide, into: [], do: l
length c
end

def count(strand, nucleotide) do
c = for l <- strand, l = nucleotide, into: [], do: l
length c
end
end``````
``````add_subscription(user, subscription)
``````

No pattern matching.

``````def add_subscription(_user, _subscription) do
``````

No pattern matching. Leading underscores simply indicate to the compiler that the arguments (i.e. data) are deliberately being ignored - otherwise the compiler would warn about unused parameters (i.e. names).

``````def add_subscription(%User{subscription: nil} = user, subscription) do
``````

There are two things going on here

``````%User{subscription: nil}
``````

Yes, this is a map pattern match (on a struct which is more rigid than a map). However map matching “feels” a bit different because the match is “partial”. In this particular case the value under “subscription” key has to be `nil` - but there are no constraints on the match with regards to the remaining keys in the structure whatever they are.

``````%User{subscription: nil} = user
``````

This binds the `user` argument to the whole matched structure. This is useful if you want a particular match but you intend to use the matched structure as a whole (i.e. you don’t have to “recreate it” when using it in another function invocation or returning it as is).

seems close but it’s not working

Which test case is failing?

``````# file: nc.exs
defmodule NucleotideCount do

def count(strand, nucleotide) do
c = for l <- strand, l == nucleotide, into: [], do: l
length c
end

end

IO.inspect(NucleotideCount.count('AATAA', ?A))
IO.inspect(NucleotideCount.count('AATAA', ?T))
IO.inspect(NucleotideCount.count('', ?A))
IO.inspect(NucleotideCount.count('AAAAA', ?A))
``````
``````\$ elixir nc.exs
4
1
0
5
\$
``````

I wonder why checking

``````IO.inspect(NucleotideCount.count('AATAA', ?A))
``````

is not the same as checking:

``````IO.inspect(NucleotideCount.count('AATAA', 'A'))
``````

against `?A` is not the same as checking against `'A'`, since `?` gets a character code point and a charlist is nothing more than a list of code points https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html

Thank you for your help!

Sorry @peerreynders.

The test with `==` is not failing. The reason is that I was checking against `'A'`, not against `?A`. Please see my newer answer to @kokolegorille

Shouldn’t the expression with the pattern matching also work?

``````IO.inspect(Kernel.is_binary("string"))   # true
IO.inspect(Kernel.is_list("string"))     # false
IO.inspect(Kernel.is_binary('charlist')) # false
IO.inspect(Kernel.is_list('charlist'))   # true
IO.inspect(Kernel.is_list('A'))          # true
IO.inspect(Kernel.is_integer('A'))       # false
IO.inspect(Kernel.is_list(?A))           # false
IO.inspect(Kernel.is_integer(?A))        # true
``````
2 Likes

Because ?A is 65 while ‘A’ is [65]

2 Likes