# Prime factors with multiplicity

This is the function I came up with:

Flatten[ConstantArray @@@ FactorInteger[#]] &


Is there a way to write this cleaner or point-free?

Update: I only have Mathematica 12 Student Edition. Seems like MapApply is new in 13.1.

Notes on Point-Free

Point-free style, also known as tacit programming, defines functions without reference to formal arguments. See wikipedia: Tacit programming, YouTube: Point-free or Die. In the Wolfram Language, a point-free alternate to f[x_] := g[h[x]] would be f = g @* h. There are also some built in forms that facilitate a point-free style: Map[f, #]& becomes Map[f]; SortBy[#, f]& becomes SortBy[f]; StringReplace[#, rules]& becomes StringReplace[rules]. Mathematica provides these functions in non-curried and curried forms. Partial application is demonstrated here with the curried form. The benefit of point-free style is emphasis on function composition instead of the arguments.

• What is the intended output?
– Syed
Aug 22, 2023 at 3:39
• What does "point-free" mean? Aug 22, 2023 at 4:08
• The function with argument 12 should return {2,2,3}. Point-free meaning without mention of the argument, just by function composition.
– qwr
Aug 22, 2023 at 4:20
• If you have the appropriate combinators, it is ALWAYS possible to transform code into point free code. For Haskell, see pointfree.io Aug 23, 2023 at 17:40
• @user1066 yes I think that works. I was just a little confused on composition @* versus Apply @@.
– qwr
Aug 23, 2023 at 21:46

Flatten@*MapApply[ConstantArray]@*FactorInteger

• That’s ghastly. Gets my vote. Aug 22, 2023 at 4:42
• @DanielLichtblau actually this is almost exactly what I'm looking for. Unfortunately my Mathematica version doesn't have MapApply.
– qwr
Aug 22, 2023 at 22:13
• You can replace MapApply[...] with Map[Apply[...]](see @Syed's answer for examples) Aug 22, 2023 at 22:34
• It’s a fine answer, actually. Which is the real reason it got my vote. Aug 23, 2023 at 1:37

For versions prior to v13.1:

g = Map[Apply[Sequence]]@*Map[Apply[ConstantArray]]@*FactorInteger


or

h = Flatten@*Map[Apply[Table]]@*FactorInteger;


Example:

g /@ Range[100, 600, 50]


{{2, 2, 5, 5}, {2, 3, 5, 5}, {2, 2, 2, 5, 5}, {2, 5, 5, 5}, {2, 2, 3, 5, 5}, {2, 5, 5, 7}, {2, 2, 2, 2, 5, 5}, {2, 3, 3, 5, 5}, {2, 2, 5,
5, 5}, {2, 5, 5, 11}, {2, 2, 2, 3, 5, 5}}

☺ = InternalRepetitionFromMultiplicity @* FactorInteger;

☺ @ 120

{2, 2, 2, 3, 5}

☺☺ = MapApply[Splice @* Table] @* FactorInteger;

☺☺ @ 120

{2, 2, 2, 3, 5}

• I assume the Internal function isn't guaranteed stable across versions?
– qwr
Aug 22, 2023 at 17:19

This is perhaps the most obvious rewrite of your function that does not use infix operators (@, @@ etc) and is a little more readable, at least to me:

f = Function[
{n},
Flatten[Apply[ConstantArray, FactorInteger[n], 1]]
];

f[120]

(* Out: {2, 2, 2, 3, 5} *)
$$$$

• I don't think the OP was looking for ways to remove infix notation. I think OP wanted a point-free style (or a cleaner style, but since clean is subjective, I'm ignoring that). This solution still references arguments (specifically the argument named "n"), and so isn't point free. Aug 22, 2023 at 23:17
• @lericr what does "point-free" mean in this context? I'm unfamiliar with that expression. Aug 22, 2023 at 23:48
• @MarcoB "Point" is just a synonym for "argument". So, "point-free" means "no reference to arguments (as in formal arguments or placeholders, you'll obviously pass in values when you eventually want to apply your function). You typically build up a point-free implementation by starting with whatever primitive functions you have and using composition. So, instead of f[g[#]]& you'd use f @* g. Instead of f[x_] := Sin[Sqrt[x]] you'd use f = Sin @* Sqrt. "Tacit programming" is perhaps a better term. I enjoyed this video: Point-Free or Die. Aug 23, 2023 at 0:18
• @MarcoB Also, in functional programming (an undefined term that I won't try to define rigorously here) it's often convenient to have point-free representations of functions since functions are "first class objects" and you want to pass them around or map them or whatever without having to deal with managing all of the (formal) arguments. Aug 23, 2023 at 0:26
• @lericr I see. That's interesting, thank you! I'd never come across the term before. Perhaps you might consider adding your explanation to the question for clarity, or maybe a link to an explanation? Aug 23, 2023 at 1:57
Sequence@@@ConstantArray@@@FactorInteger@120

(* {2, 2, 2, 3, 5} *)


Or, using RightComposition, where the first function called is furthest left, allowing 'normal' left-to-right reading.

FactorInteger/*MapApply[ConstantArray]/*MapApply[Sequence]@120

(* {2, 2, 2, 3, 5} *)

RightComposition[FactorInteger,MapApply[ConstantArray],MapApply[Sequence]]@120

(* {2, 2, 2, 3, 5} *)

• If RightComposition is used to read left-to-right, then input 120 should be on the left. Maybe with postfix //?
– qwr
Aug 24, 2023 at 16:14