Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elixir: What kind of list is this with the vertical bar still in it?

Tags:

elixir

I'm digging through how Phoenix renders templates as iodata, and I found some lists that look odd to me. It seems that I'm missing a basic bit of syntax for lists involving the "vertical bar" or "vertical pipe" character (|).

Here are some examples I do understand:

# prepends 1 to the list [2, 3]
l = [1 | [2, 3]] #=> [1, 2, 3]

# matches the head and tail into variables
inspect_tail = fn ([_head | tail]) -> IO.inspect(tail) end

Those I get. But what is this?

l = ["hi" | "there"] #=> ["hi" | "there"]

It seems to be a list with a head and tail:

is_list(["hi" | "there"]) #=> true
hd(["hi" | "there"])      #=> "hi"
tl(["hi" | "there"])      #=> "there"

...but the length(list) function gives an ArgumentError if given a list like this.

What is it, and what is it used for?

like image 480
Nathan Long Avatar asked Apr 29 '16 19:04

Nathan Long


People also ask

What is a vertical stacked bar chart?

A vertical stacked bar chart is a type of bar graph that uses vertical bars to compare individual data variables. This statistical tool stacks data categories so that each bar shows the total number of subcategories that make up a data set.

What does the vertical bar symbol mean in math?

The vertical bar symbol is used in math to represent the absolute value operator. Typically the symbol is used in an expression like this: In plain language, this means take the absolute value of the value −3 which is equal to 3. To vertical bars on either side of a vector represent taking the magnitude or length of that vector

What is the best healthy grains kind bar?

and the #1 best healthy grains kind bar is… MAPLE PUMPKIN SEEDS WITH SEA SALT Nutrition: 150 calories, 5 g fat (1 g saturated fat), 90 mg sodium, 23 g carbs, 2.5 g fiber, 6 g sugar, 3 g protein


2 Answers

Improper list is correct.

I'll quote a note from Learn You Some Erlang, which sums it up nicely.

Note: Using the form [1 | 2] gives what we call an 'improper list'. Improper lists will work when you pattern match in the [Head|Tail] manner, but will fail to be used with standard functions of Erlang (even length()). This is because Erlang expects proper lists. Proper lists end with an empty list as their last cell. When declaring an item like [2], the list is automatically formed in a proper manner. As such, [1|[2]] would work! Improper lists, although syntactically valid, are of very limited use outside of user-defined data structures.

like image 163
jisaacstone Avatar answered Oct 24 '22 06:10

jisaacstone


It is indeed an improper list, so-called because, unlike a proper list, which has a head element and a tail that is itself a list, an improper list ends in not-a-list, because the last element is neither a cons cell nor nil. (Confused by cons cell / nil verbiage? See end.)

You can check out out the inspect tests for an improper list here to see it in action.

You'll find functions that work fine with it, like hd/1, have an argument type spec'd as maybe_improper_list, while others, like length/1, expect a proper list only.


If you don't have a Lisp background, that cons cell / nil bit might be confusing.

"Nil" is basically "the empty list", but I find calling it that leads to a circular definition of what a list is: "a list is either a head element tied to a tail that's itself a list, or it's the empty list" leads to "Gee, I never would have guessed an empty list was a list! Thanks for enlightening me! :rolleyes:"

By distinguishing nil as its own special thing, we get to say, "Nil is a list, and you can build another list by consing a single element onto a list." That's a decent inductive datatype definition there. :)

like image 39
Jeremy W. Sherman Avatar answered Oct 24 '22 06:10

Jeremy W. Sherman