scicloj / wolframite

An interface between Clojure and Wolfram Language (the language of Mathematica)
https://scicloj.github.io/wolframite/
Mozilla Public License 2.0
56 stars 2 forks source link

Cannot define functions the same way as Wolfram (using Pattern and Blank, not Function) #74

Closed light-matters closed 2 months ago

light-matters commented 4 months ago

When writing the docs for said behaviour, I came across this issue (which I'm not sure existed previously).

(wl/eval (wl/->clj "SetDelayed[f[Pattern[x, Blank[]]], Power[x, 2]]"))

Returns "$Failed". The string can be evaluated inside Wolfram fine and corresponds to a basic function definition:

f[x_]:=x^2

I can get the desired behaviour with

(wl/eval (w/_= 'f (w/fn [x] (w/Power x 2))))

, but this is only because w/fn is an especially coded exception.

It's also worth noting that we can no longer write

(wl/eval ((w/Function 'x
                      (w/Power 'x 2)) 
                5))

, but instead must write

(wl/eval ((wl/eval (w/Function 'x
                               (w/Power 'x 2))) 5))
holyjak commented 2 months ago

Ok, so the following two approaches work:

(wl/eval (w/_= 'f (w/fn [x] (w/Power x 2))))
=> nil
(wl/eval '(SetDelayed f2 (Function [x] (Power x 2))))
=> nil
(wl/eval "SetDelayed[f3, Function[{x}, Power[x, 2]]]")

(wl/eval '(f 2)) ; or f2, or f3
=> 4

but this, which should be equivalent except that it uses not Function but Pattern + Blank, does not:

(wl/eval "SetDelayed[f[Pattern[x, Blank[]]], Power[x, 2]]")
=> $Failed

(-> (wl/wolfram-expr "SetDelayed[f[Pattern[x, Blank[]]], Power[x, 2]]") 
      (wolframite.base.convert/convert {:jlink-instance (wolframite.impl.jlink-instance/get)}))
=> #object[com.wolfram.jlink.Expr 0x31a78c09 "SetDelayed[f[Pattern[x, Blank[]]], Power[x, 2]]"]
(wolframite.base.evaluate/evaluate *1 {:jlink-instance (wolframite.impl.jlink-instance/get)})
=> #object[com.wolfram.jlink.Expr 0x2b6a7d2 "$Failed"]

So the seemingly same SetDelayed... call behaves differently. TODO: Explore the Expr instace in detail. Its string representation could mean different things... .

In Wolfram, this works:

In[4]:= SetDelayed[f4[Pattern[x, Blank[]]], Power[x, 2]]                                                                                                                           
In[5]:= f4[2]                                                                                                                                                                      
Out[5]= 4
holyjak commented 2 months ago

(wl/eval (wl/->clj "SetDelayed[f[Pattern[x, Blank[]]], Power[x, 2]]")) works for me now, on the improve-error-handling-on-failed-eval branch:

(wl/eval (wl/->clj "SetDelayed[f2[Pattern[x, Blank[]]], Power[x, 2]]"))
=> nil
(wl/eval '(f2 2))
=> 4

(The above is the same as directly (wl/eval '(_= (f3 (Pattern x (Blank))) (** x 2))).)