# Map function with evaluated and unevaluated parameters

Let's consider a function with evaluated and unevaluated arguments inside:

list1 = {1,2,3}
list2 = {x,y,z}

fun[list_]:={list,ToString@Unevaluated@list}


When I use Map over fun I expect to get result like this:

{fun[list1],fun[list2]}
(*{{{1, 2, 3}, "list1"}, {{x, y, z}, "list2"}}*)


But instead I get this:

fun /@ {list1, list2}
{{{1, 2, 3}, "{1, 2, 3}"}, {{x, y, z}, "{x, y, z}"}}


This is surely connected with my misunderstanding of evaluation behaviour, but no obvious answer was found in Robby Villegas notebook https://library.wolfram.com/infocenter/Conferences/377/ , nor here in StackExchange. How to solve this problem?

ver. 12.1, Windows 10

EDIT
Setting attribute Listable help a bit making unnecessary to use Map:

SetAttributes[fun, {HoldAll, Listable}];
fun[{list1,list2}]

(*{{{1, 2, 3}, "list1"}, {{x, y, z}, "list2"}} *)


It is the Map command which needs to use HoldAll. This is one way to make it work. There might be other ways

SetAttributes[fun, HoldAll];
SetAttributes[Map, HoldAll]
fun[list_] := {ToString@HoldForm@list, list}
list1 = {1, 2, 3}
list2 = {x, y, z}
fun /@ {list1, list2}


If you do not add SetAttributes[Map, HoldAll] then this is what you get

This shows that Map is the one which evaluated its argument, so too late by the time it reaches your function.

• Thank You for Your answer. Feb 11 at 14:12

The keypoint is, if a function doesn't have a Hold* attribute, its argument(s) will always be evaluated before going into the function. So in your case, you need to stop the automatic evaluation 3 times. One for Map (/@), one for fun and one for ToString. You've already properly handled ToString with an Unevaluated and fun with the HoldAll attribute. For Map, you just need one more Unevaluated:

list1 = {1,2,3};
list2 = {x,y,z};

SetAttributes[fun, HoldAll]
fun[list_]:={list,ToString@Unevaluated@list}
fun /@ Unevaluated@{list1, list2}


Setting HoldAll attribute on Map as shown in Nasser's answer is another way to go, but generally it's not a good idea to modify built-in functions. BTW, if you don't want to set HoldAll on fun, you can introduce a pure function as the wrapper as follows:

ClearAttributes[fun, HoldAll]

Function[a, fun@Unevaluated[a], HoldAll] /@ Unevaluated@{list1, list2}


Notice the HoldAll inside Function stops the automatic evaluation of argument of pure function, and the Unevaluated inside Function stops the automatic evaluation of argument of fun.

• very simple and clear explanation, thanks for Your help! Feb 11 at 14:12