function on parts of lists works only in pure function?

For example, I'd like to take the first four upper left values of a matrix, i.e.

f[x_] := f[x] = x[[;; 2, ;; 2]];

This works nicely, e.g. f[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}]= {{1, 2}, {4, 5}}

Now, I was trying to ged rid of the delayed evaluation and just use f[x_]=... which doesn't work: Part::take: Cannot take positions 1 through 2 in x.

But if I define the function like this, it works:

f = #[[;; 2, ;; 2]]&;

Why is this? And how would I do it in the f[x_]=pattern?

Of course, I could just use delayed evaluation but in another case I have a more complicated funtion

g[x_,y_]=x[[;; 2, ;; 2]]+expensiveFunction[y]

where I would like the g[x]part to be evaluated delayed and the g[y] part evaluated at the time of definition.

Ultimately, I would even like Mathematica to recognize that by x[[;; 2, ;; 2]] I have a 2x2 matrix and further functions of that 2x2 matrix are already evaluated without knowing the values there (e.g. determinant or trace):

h[x_,y_]=expensiveFunction1[x[[;; 2, ;; 2]]]+expensiveFunction2[y]
• Wait, why are you trying to get rid of delayed evaluation? I think delayed evaluation is exactly what you need, i.e. just use f[x_] := x[[;; 2, ;; 2]]; – Mr.Wizard Feb 17 '17 at 14:35
• for this simple function, yes. But let's assume I have multiple arguments and for the sake of speed I would like to have the evaluation already performed for the other arguments. Ideally, I would like to process even the matrix elements, for example getting the determinant or trace already (immediately evaluated). So I guess this is all possible when using the pure function notation. But for readability it might be easier to use speaking variable names. [Note, SetAttributes[f, HoldFirst]; f[x_] = x[[;; 2, ;; 2]]; (as you just suggested before editing) gives the same error.] – riddleculous Feb 17 '17 at 14:45
• Sorry about the totally misguided suggestion; my gut reaction before reading more carefully was that that would help. I still do not understand what you are asking however. You start by showing a memoizing construct which sounds like what you are saying you want, but then apparently you don't want it. Please edit your question to include a complete example that illustrates how f[x_] := f[x] = x[[;; 2, ;; 2]]; does not do what you want. – Mr.Wizard Feb 17 '17 at 14:48
• yes I realized that, sorry! Is it clear now? – riddleculous Feb 17 '17 at 14:51

There is similarity to a question that came up yesterday; you might take a look:

If we assume that expensiveFunction works symbolically on a single parameter the code you wrote already works as-is despite the warning message from Part:

expensiveFunction = Total[#^Range] &;

g[x_, y_] = x[[;; 2, ;; 2]] + expensiveFunction[y];

?g
g[x_, y_] = y + y^2 + y^3 + y^4 + y^5 + x[[1 ;; 2, 1 ;; 2]]

If you just want to avoid that message you have several options including:

1. Quiet[g[x_, y_] = . . . , Part::take]

2. Block[{Part}, g[x_, y_] = . . . ]

3. Prevent Part[] from trying to extract parts of symbolic expressions

The first is actually the one I recommend. It really is just a warning message in this case, not an error. Block is handy but it disables Part throughout the evaluation which can potentially break code in unexpected ways. The last method is OK but really you just create another layer of evaluation that is unnecessary.

Related:

• this is really helpful, also the other questions you mentioned sound like problems that are likely to occur for me very soon, too. Will dive into them next week when I have a bit more time. Thanks a lot! – riddleculous Feb 17 '17 at 15:10
• @riddleculous Glad I could help. :-) – Mr.Wizard Feb 17 '17 at 15:11