CharacterRange documentation says that it returns a list. However, if I define

letters[n_] := CharacterRange["\[Alpha]", "\[CurlyPhi]"][[;; n]]

and then ask for Part[letters, 3], I get Part::partd. If I ask for Last[letters] I get Last::normal. What gives?

  • 1
    $\begingroup$ try n=4; Part[letters[n], 3] $\endgroup$
    – kglr
    Oct 7 '17 at 15:48
  • $\begingroup$ OK, this one is on me for using code I don't completely grok. That last bit with the n in the definition of letters, what is it doing? Are you redefining it with your statement? $\endgroup$
    – jamesson
    Oct 7 '17 at 15:51
  • $\begingroup$ jamesson, see tutorial/DefiningFunctions $\endgroup$
    – kglr
    Oct 7 '17 at 15:58
  • $\begingroup$ If you really don't understand what functions are (in the programming sense), then it's time to go through a basic tutorial: wolfram.com/language/elementary-introduction/2nd-ed There is a minimum level of expected Mathematica knowledge before asking on this website. $\endgroup$
    – Szabolcs
    Oct 7 '17 at 18:36
  • $\begingroup$ No, trust me, I know what a function is :). I have spent the past 2 hours reading about Mathematica scope, it is... interesting. $\endgroup$
    – jamesson
    Oct 7 '17 at 18:39

While e.g., letters[5] (or any other integer between 1 and 22) is a list, letters is not. Colloquially, letters is a function, which is implementing in Mathematica as a symbol with DownValues.

You can think of DownValues as rules which are applied during the sequence of evaluation, so that letters[5] evaluates to {"α", "β", "γ", "δ", "ε"}.

In fact, you can query the DownValues of letters with fairly readable results:

DownValues[ letters ]
{ HoldPattern[letters[n_]] :> CharacterRange["α", "φ"][[1 ;; n]] }

(HoldPattern is just a way of making sure the left hand side of the rule doesn't evaluate before the rule can be applied.)

Your problem was two-fold:

  1. No subpart of letters[[3]] is of the form letters[n_], so the DownValue couldn't apply
  2. More noticeably, Part immediately tries to evaluate, even if its first argument has insufficient length/depth, which results in your error.

If you'd like to use the syntax letters[[3]] to return "α", you can instead redefine letters:

ClearAll[ letters ]  (* Remove DownValues *)
letters = CharacterRange["α", "φ"];

{"α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "ς", "σ", "τ", "υ", "φ"}

Fun fact: while SetDelayed (:=) statements are stored as rules in DownValues, Set (=) statements are stored in OwnValues :

 OwnValues[ letters ]  (* after using `=` rather than `:=` *)
{ HoldPattern[letters] :> {"α", "β", "γ", "δ", "ε", "ζ", "η", "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", "π", "ρ", "ς", "σ", "τ", "υ", "φ"} }
  • $\begingroup$ Very cool, I must study this $\endgroup$
    – jamesson
    Oct 7 '17 at 18:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.