# 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"}}*)


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.

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, 2023 at 14:12