EasyArray / phosphorus

1 stars 0 forks source link

explicit function issues #4

Open EasyArray opened 2 years ago

EasyArray commented 2 years ago
havijw commented 2 years ago

I think having a class for explicit functions is a good idea, and it could even replace the set class (a set would be a function that maps every input to None). Is there ever a reason we'd want a function as the input to another function though? This wouldn't be possible using dict, since they are hashable, and I don't think frozendict is built into Python...

EasyArray commented 2 years ago

I'm starting to wonder if these should actually be LambdaVal's? Pros / Cons for that idea? There would be a different syntax, maybe something like: λ{ 1→2, 2→4, 3→6 }

havijw commented 2 years ago

This seems reasonable. Under the hood it might get a little bit complicated because (the way I imagine it) you'd have two different representations depending on whether the function is an actual lambda or an explicit function, but it would make all functions the same.

EasyArray commented 2 years ago

I was thinking that we could store the explicit function as the body of a standard LambdaVal. The body is a "Span" so it's basically just some phosphorus code that later gets evaluated. So (note the square brackets, like the book uses), λ[1→2, 2→4, 3→6] might be stored exactly like the phosphorus lambda function λx . {1:2, 2:4, 3:6}[x] . (Modulo the problem you noted with dicts: I don't know if LambdaVals are hashable.)

EasyArray commented 2 years ago

Update: LambdaVal's are not hashable. But we could make them so, if we wanted: https://hynek.me/articles/hashes-and-equality/

EasyArray commented 2 years ago

Yes, was thinking something along those lines. Probably the easiest, actually, would be to hash them based on their repr. This would not be perfect, as in the same function with a slightly different definition would not hash the same, but it would probably suffice for our purposes. Especially since we are hand-creating these explicit function LambdaVals and can do things like sorting to canonicalize the reprs.

havijw commented 2 years ago

Yeah I think this should be relatively straightforward, although I don't know how storing as a Span affects things. But Python functions are hashable so in principle we could just get the corresponding Python lambda and hash that.

EasyArray commented 2 years ago

Ha, I think we are commenting at the same time -- check my comment about hashing the repr

havijw commented 2 years ago

Yep that makes a lot of sense! Is this something I should look into? It seems like this might be something that happens when things are parsed - allowing LambdaVals to be constructed with explicit functions. Also, should sets that are explicit functions be automatically turned into LambdaVals?

Something I can do is take out the ability of SetVals to be called as explicit functions. This would simplify SetVal.__call__ quite a bit! But I assume that shouldn't be done until whatever we're doing with explicit functions as LambdaVals is implemented.

EasyArray commented 2 years ago

You are right that this is perhaps a parsing / input conversion issue. I'm thinking that sets will not (any longer) automatically get interpreted as explicit functions. Instead, the new syntax will be required, and will generate a LambdaVal. Some care will have to be used in generating a repr for such a LambdaVal, since it might be confusing to input something like λ[1→2, 2→4, 3→6] only for the system to output λx . {1:2, 2:4, 3:6}[x]. Perhaps LambdaVal could store a flag as to whether it is an explicit or code-based function? And then print out explicit functions as they were input.

To this end, perhaps you could do the following:

I will work on parsing the explicit format correctly (shouldn't be too hard) -- just let me know the "API" for the LambdaVal constructor. We can later turn off the logic for explicit functions in SetVal.__call__.

havijw commented 2 years ago

Great! This sounds doable.

havijw commented 2 years ago

I'm having a little trouble understanding how LambdaVals work, so this is not going too well. For instance, I'm not sure what the current arguments of the constructor function are or what they do later on. I think maybe I need to learn a little more about parsing — do you have any recommendations for resources? Or if you have other ideas for figuring out how these objects work, that would be great! I have some debugging tools with JupyterLab, so maybe seeing how things flow as the notebook runs would be helpful? I'm open to ideas!

havijw commented 2 years ago

Never mind, I figured it out! VSCode's Jupyter debugging tools are incredible — exactly what I needed. I just stepped through the parse/constructor functions and was able to figure everything out. I think I have everything done now, so I'll do a bit of testing and hopefully push a version for you to look at tomorrow.

EasyArray commented 2 years ago

Great! I should try out VSCode again -- do you mind sending me your configuration / plugins /etc? Oh, and also could you document what you found out / what confused you at first, if you haven't already?

havijw commented 2 years ago

Sure! I love VSCode. The one drawback is that tab-completion doesn't work in Jupyter notebooks, which makes using Phosphorus a pain sometimes. But the debugging is great — exactly what I wanted with stepping into function calls in phosphorus etc.

The relevant Python/Jupyter extensions I have are: Python, Pylance, Jupyter, Jupyter Keymap, and Jupyter Notebook Renderers, all from Microsoft. I'm not sure if it affects anything, but I also have the following in my settings file:

"python.showStartPage": false,
"workbench.editorAssociations": {
    "*.ipynb": "jupyter-notebook"
},
"python.pythonPath": "~/miniforge3/bin/python",
"python.defaultInterpreterPath": "~/miniforge3/bin/python",
"notebook.cellToolbarLocation": {
    "default": "right",
    "jupyter-notebook": "left"
},

The miniforge path is just where I have the conda installation.

I will definitely add some documentation for what I figured out!