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?
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.
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
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
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.
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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With