1

There are some basic instructions about Composition on this site, but I'm still confused on how to use it when the functions I am composing have two parameter, such as:

t := RandomImage[1, {50, 50}, ColorSpace -> "RGB"]
picList = Array[t &, 3];
ImageResize[#, 500] &@*ColorConvert[#, "Grayscale"] & /@ picList

Mathematica graphics

But when the composition functions just have one parameter, the behavior is more predictable:

hh@*ff /@ picList

Mathematica graphics

Can anybody explain this strange behavior?

yode
  • 26,686
  • 4
  • 62
  • 167

1 Answers1

3

& has a very low operator precedence, in particular it's lower than @*'s precedence. That means that the right-hand & is actually defining an unnamed function with the body:

ImageResize[#, 500] & @* ColorConvert[#, "Grayscale"]

You can fix this by wrapping the right-hand function in parentheses:

ImageResize[#, 500] & @* (ColorConvert[#, "Grayscale"] &) /@ piclist

Or both of them for consistency:

(ImageResize[#, 500] &) @* (ColorConvert[#, "Grayscale"] &) /@ piclist

Of course, as you mentioned in a comment, that doesn't help much compared with

(ImageResize[#, 500] &) /@ (ColorConvert[#, "Grayscale"] &) /@ piclist

If you want to avoid the parentheses altogether, you could still define a pure function via the Function, but of course, that's even less terse, and technically you've just replaced parentheses with square brackets:

Function[ImageResize[#, 500]] @* Function[ColorConvert[#, "Grayscale"]] /@ piclist

You can also use the full form of @* instead:

Composition[ImageResize[#, 500] &, ColorConvert[#, "Grayscale"] &] /@ piclist

Alternatively, you could apply both transformations in a single function:

ImageResize[ColorConvert[#, "Grayscale"], 500] & /@ piclist

Or use infix notation for a nicer reading order:

# ~ColorConvert~ "Grayscale" ~ImageResize~ 500 & /@ piclist
Martin Ender
  • 8,774
  • 1
  • 34
  • 60