0
$\begingroup$

Consider the following definition of splitList:

elem[list_List, i_Integer] := list[[i]]
splitList[list_, size_Integer] := Table[elem[list, i], {i, size}]

Example use is like splitList[f[x], 3] to get a list of 3 symbolic expressions, which would expand to f[x][[1]], f[x][[2]] and f[x][[3]] when x attains such a value as to make f[x] a true List. I can't use literal list[[i]], since f[x] is not a list initially, so I'd get Part::partd error.

Here elem is a function used only once, so it'd be good to avoid even naming it. Naturally, I thought I'd use a pure function for this. But then I come across a problem: my naïve approach doesn't work: the following code

splitList[list_, size_Integer] := Table[Function[{x_List,i_Integer},list[[i]] ], {i, size}]

emits an error message:

Function::flpar: Parameter specification {x_List,i_Integer} in Function[{x_List,i_Integer},f[x][[i]]] should be a symbol or a list of symbols.

So, apparently, I can't use patterns in Function. How can I constrain parameters of a pure function then?

$\endgroup$
3
  • 1
    $\begingroup$ You will have a better chance of getting an answer if you explain why you want to constrain the variable types, and what semantics (kinds of actions) you expect when the types don't match (e.g. return the call unevaluated, return $Failed or Failure object, throw an exception, abort the surrounding Table call or loop, etc). $\endgroup$ Apr 14, 2020 at 10:22
  • $\begingroup$ @LeonidShifrin well, I thought I explained it in the paragraph right after the first snippet: I need to avoid Part::partd errors on list[[1]] and siblings, and if the types don't match, the behavior should be to leave the expression unevaluated. Basically, I need the functionality of the first snippet, but without naming the elem function. $\endgroup$
    – Ruslan
    Apr 14, 2020 at 10:30
  • $\begingroup$ Well, the "nameless" nature of pure functions is only useful not just when you need to use it only once, but when you need to use it once within the same evaluation. In your case, the elem function carries certain semantics for what heppens in between evaluations: whenever list is not a list, it preserves the call unevaluated. So it is used in more than one evaluation, separated by some time interval (the second one is when list actually becomes a list, thus allowing it to evaluate). So this strategy of replacing with Function does not seem applicable: Function always evaluates. $\endgroup$ Apr 14, 2020 at 10:43

2 Answers 2

1
$\begingroup$

One way of solving the problem of cluttering the global namespace is to use Module with a locally-named function, like here:

splitList[list_, size_Integer] := 
 Module[{elem},
  elem[data_List, i_Integer] := data[[i]];
  Table[elem[list, i], {i, size}]
 ]

This way, although we still give our helper function a name, it's no longer in the global namespace (it's instead automatically suffixed with something like $2034 with ever-increasing number), so we can reuse the name elem however we like without interfering with splitList. So, it's basically like a pure function, but with a hidden name.

$\endgroup$
1
  • 1
    $\begingroup$ Keep in mind that these local symbols will not be garbage-collected and will be accumulating and cluttering the global namespace.And yes, they still live in global namespace, making them local to the Module does not change that. $\endgroup$ Apr 14, 2020 at 11:22
0
$\begingroup$

What about the following code?

Input:

Clear[splitList, elem, f]
splitList[list_, size_] := Quiet[Take[list, size]]
test = splitList[f[x], 10]
f[x] = Range[10];
test

Output:

Take[f[x], 10]
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

Variable test is set the value Take[f[x], 10] and keeps unevaluated until f[x] is set to be some list.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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