5
$\begingroup$

Say, I want to take the first part of an operation in a function:

In: func[operexpr_] := operexpr[[1]];
    func[a < b]

Out: a

But every once in a while a numerical representation of both a and b will end up being passed to the function.

Outside the function, this can be simply

In: Unevaluated[2 < 3][[1]] 

Out: 2

But how do I do this in a function?

In: func[operexpr_] := Unevaluated[operexpr][[1]];
    func[2 < 3]

Out: Unevaluated[True][[1]]
(* ^ doesn't work *)

In: func[operexpr_] := operexpr[[1]];
    func[Unevaluated[2 < 3]]

Out: True[[1]]
(* ^ still doesn't work *)

In: func[operexpr_] := Unevaluated[operexpr][[1]];
    func[Unevaluated[2 < 3]]

Out: True[[1]]
(* ^ still doesn't work *)

How do I go about this? I know it's odd that an operation with fully evaluable values on both sides will be passed to the function and have to be broken down still (most of the time the "True" result is all we need). But, I'm doing operations with inequalities and treating it this way makes the implementation easy and short (this being a nuisance), which I favour when I write in scripting languages.

Also, it makes it possible to easily debug the larger function I'm actually constructing. By passing numerical values.

$\endgroup$
2
  • $\begingroup$ One possibility: func[operexpr_] := Defer[operexpr][[1, 1]]. I would have though that SetAttributes[func, HoldFirst], would work, but I guess once it hits Part, the expression must get evaluated in order to extract parts of it? I'm not sure. $\endgroup$
    – march
    Sep 20, 2016 at 20:13
  • $\begingroup$ Awesome! That seems to have done the trick. $\endgroup$
    – kozner
    Sep 20, 2016 at 20:18

2 Answers 2

6
$\begingroup$

This is very easy with destructuring.

SetAttributes[f, HoldFirst];
f[h_[a_, b_]] := a

f[x < y]

x

f[2 < 3]

2

a = 1; b = 2; f[a < b]

1

$\endgroup$
1
  • $\begingroup$ I like this one... Sanely functional. $\endgroup$
    – kozner
    Sep 20, 2016 at 20:46
2
$\begingroup$

This is a job for any number of commands in Mathematica that keep an expression from being evaluated. However, some of them require setting the HoldAll or HoldFirst Attribute, and some don't:

SetAttributes[f1, HoldAll];
f1[operexpr_] := Defer[operexpr][[1, 1]]
f1[2 < 3]
(* 2 *)

or

SetAttributes[f2, HoldAll]
f2[operexpr_] := First@Inactivate[operexpr]
f2[2 < 3]
(* 2 *)

or

SetAttributes[f3, HoldAll]
f3[operexpr_] := First@Unevaluated[operexpr]
f3[2 < 3]
(* 2 *)
$\endgroup$
2
  • $\begingroup$ I feel like I'm being left out of the loop with using these prefixes, internal evaluation precedence and seeing what works and doesn't. Is this set by the Mathematica language itself (documented) or just specific to the current version of the engine? $\endgroup$
    – kozner
    Sep 20, 2016 at 20:43
  • $\begingroup$ @kozner. Maybe a mixture of all three? I just learn by doing for the most part. See this answer and the link to an SO question therein for use cases for Defer, Unevaluated, Inactivate, and Hold. $\endgroup$
    – march
    Sep 20, 2016 at 21:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.