Pattern Matching a single-element list

3,267 views
Skip to first unread message

Britt Lewis

unread,
Jan 19, 2015, 12:20:45 AM1/19/15
to elixir-l...@googlegroups.com
I'm still getting used to the conventions and best practices surrounding Elixir pattern matches, and I'd appreciate some feedback about the preferred way to match a single element list. The two ways I can think of are matching the empty tail in the argument list, versus using a length guard clause. For all you visual people:
# empty tail pattern match:
def func(list = [_head | []]), do: list
# length guard match:
def func(list) when length(list) == 1, do: list
I recognize this is largely a question of style/readability and therefore subjective, but I'm interested in hearing which way those of you prefer who've developed more of a sense for questions like these.

Thanks!
Britt

Adam Kittelson

unread,
Jan 19, 2015, 12:27:23 AM1/19/15
to elixir-l...@googlegroups.com
I'm not sure what the convention is, but the first option could be pared down to:

def func([_] = list), do: list

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Greg Vaughn

unread,
Jan 19, 2015, 12:48:05 AM1/19/15
to elixir-l...@googlegroups.com
I wouldn't do quite either one, but instead:

def func(list = [_single])

My general approach is that pattern matching is plan A; guard clauses are plan B -- in those few cases where both are capable of a particular constraint.

That being said, it feels strange to me that I'd want to name the whole list with a single element, but underscore-ignore the actual single element itself. Perhaps it's just a contrived example though.

-Greg Vaughn

Britt Lewis

unread,
Jan 19, 2015, 1:20:42 AM1/19/15
to elixir-l...@googlegroups.com

On Monday, January 19, 2015 at 12:48:05 AM UTC-5, Greg Vaughn wrote:
I wouldn't do quite either one, but instead:

def func(list = [_single])

My general approach is that pattern matching is plan A; guard clauses are plan B -- in those few cases where both are capable of a particular constraint.

I think I've been following this as well, without realizing it.
 
That being said, it feels strange to me that I'd want to name the whole list with a single element, but underscore-ignore the actual single element itself. Perhaps it's just a contrived example though.

It certainly is contrived -- perhaps knowing more would help illuminate the best approach (or another one I haven't considered?). 

I'm implementing a recursive divide-and-conquer algorithm for counting the inversions in an array -- the base cases are when the input has been subdivided such that the array has only one element (or in the case of an odd-length input, zero elements). In either case, there can be no inversions, so that is returned with no additional work. However, in order to take advantage of merge-sort to detect the split inversions (those inversion pairs that have an element on each side of the divided input), I need to return the array in addition to the inversion count. So my first two function clause definitions are as such:

defp sort_and_count([]), do: {[], 0}
defp sort_and_count(list = [_head]), do: {list, 0}
 
But now that I'm not explicitly matching the empty tail, perhaps I should just return a new list with the single element rather than match the full list and the individual element instead:

defp sort_and_count([]), do: {[], 0}
defp sort_and_count([head]), do: {[head], 0}

Thanks for your insight!
Britt

Saša Jurić

unread,
Jan 19, 2015, 2:50:40 AM1/19/15
to elixir-l...@googlegroups.com
I think in this example the difference is more than just stylistic differences since length/1 is O(n) operation. 

Regarding preferred style, your last snippet (defp sort_and_count([head]), do: {[head], 0})  looks nice to me.

Vincent Siliakus

unread,
Jan 19, 2015, 9:53:04 AM1/19/15
to elixir-l...@googlegroups.com
 
Op maandag 19 januari 2015 06:48:05 UTC+1 schreef Greg Vaughn:
I wouldn't do quite either one, but instead:

def func(list = [_single])

Maybe a bit pedantic, but I would stick to writing it like def func([_single] = list) instead of def func(list = [_single])

While both behave the same, the latter looks like an assignment instead of a match (or for an Elixir novice even as setting a default argument). Furthermore, both the erlang and elixir standard libraries seem to follow the
def func([_single] = list) notation.

-vincent

 
Reply all
Reply to author
Forward
0 new messages