fsprojects / IfSharp

F# for Jupyter Notebooks
Other
441 stars 71 forks source link

Provide function signature by default #131

Closed cgravill closed 7 years ago

cgravill commented 7 years ago

We print the last expression of a cell, which for some types like FSharpFunc leads to less information than on FSI:

 In[1]: let addTwo = (+) 2
        addTwo
Out[1]: <fun:addTwo@1-10>

As reported on #125. There are various workarounds e.g. .GetType().BaseType or as I suggest on the issue turning on fsioutput. That's nice to have as an option but for functions we can have a better default:

let addTwo = (+) 2
addTwo

now produces:

<fun:addTwo@1-1> : (Int32 -> Int32)

It uses reflection rather than the F# which means everything is in CLR types so there are differences to FSI e.g.

let addHigher f g = ((f 2) 3) + (g 2 3) + 5
addHigher

in the notebook:

<fun:it@2> : ((Int32 -> (Int32 -> Int32)) -> ((Int32 -> (Int32 -> Int32)) -> Int32))

while fsi:

val it : ((int -> int -> int) -> (int -> int -> int) -> int)

it might be possible to move them closer but from the obj I'm lacking in context and this seems to get a lot of the benefit.

sylvanc commented 7 years ago

Nice! CLR types is mildly unfortunate, but this is miles better than what we had previously.

dsyme commented 7 years ago

super

dsyme commented 7 years ago

(however we should definitely fix this to show F# types...)

cgravill commented 7 years ago

Turns out Unquote is doing something similar: https://github.com/SwensenSoftware/unquote/blob/924f2fb063e01288361d85dc24b9881a16e1e507/Unquote/ExtraReflection.fs#L261

I tried just using Unquote but it seems to be thrown off by the fsi generated types and just does a straight print.

cgravill commented 7 years ago

I've put in mapping according to https://technet.microsoft.com/en-us/ee353649(v=vs.85)

Does this seem better?

In [1]:
let addTwo = (+) 2
addTwo
Out[1]:
<fun:addTwo@1> : (int -> int)
In [2]:
let addHigher f g = ((f 2) 3) + (g 2 3) + 5
addHigher
Out[2]:
<fun:it@2> : ((int -> (int -> int)) -> ((int -> (int -> int)) -> int))
In [3]:
let addHigher2 f g = ((f 2.0M) 3.0) + (g 2uy 3us) + 5
addHigher2
Out[3]:
<fun:it@2-1> : ((decimal -> (double -> int)) -> ((byte -> (uint16 -> int)) -> int))
In [4]:
let addHigher3 f g = ((f 4y) "penguin") + (g 2 3.0f) + 5
addHigher3
Out[4]:
<fun:it@2-2> : ((sbyte -> (string -> int)) -> ((int -> (single -> int)) -> int))

I'm not sure how best to handle types with multiple aliases.