8000 Using F# (FSHARP) successfully · Issue #112 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Using F# (FSHARP) successfully #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
aolney opened this issue Nov 17, 2015 · 13 comments
Open

Using F# (FSHARP) successfully #112

aolney opened this issue Nov 17, 2015 · 13 comments

Comments

@aolney
Copy link
aolney commented Nov 17, 2015

I've used F# to do some of the nice dynamic interop with pythonnet rather than the c# dynamic keyword approach. Not sure if it is truly helpful over c# dynamic, but it may be a bit more concise and interesting.

Here is some code that shows the functionality. The key is to use fsprojects/FSharp.Interop.Dynamic@318f50b (actually whatever is currently available in nuget). This helped me get closer to the goal behavior of fsprojects/FSharp.Interop.PythonProvider@f3cdabf but of course without the type provider mojo (meaning user perceived behavior rather than implementation behavior). I used pythonnet from tonyroberts/pythonnet@21270eb , CPython3.4, the matching NLTK distribution, VS2015, Windows 10.

As described below the most significant complaint is that you can't use F# primitive operators like (+) on numpy arrays without an error. The workaround is to use the corresponding numpy function as demonstrated.

Also if a complicated call is made like nltk?corpus?brown?tagged_words(Py.kw("categories", "news") ) the debugger seems to time out the expression evaluation (requiring print statements). Though in general the expression evaluation on the dynamic types returned is not very helpful, so this isn't a major drawback.

open Python.Runtime
open FSharp.Interop.Dynamic
open System.Collections.Generic

[<EntryPoint>]
let main argv = 
    //set up for garbage collection?
    use gil = Py.GIL()

    //-----
    //NUMPY
    //import numpy
    let np = Py.Import("numpy")

    //call a numpy function dynamically
    let sinResult = np?sin(5)

    //make a python list the hard way
    let list = new Python.Runtime.PyList()
    list.Append( new PyFloat(4.0) )
    list.Append( new PyFloat(5.0) )

    //run the python list through np.array dynamically
    let a = np?array( list )
    let sumA = np?sum(a) 

    //again, but use a keyword to change the type
    let b = np?array( list, Py.kw("dtype", np?int32 ) )
    let sumAB = np?add(a,b)

    let SeqToPyFloat ( aSeq : float seq ) =
        let list = new Python.Runtime.PyList()
        aSeq |> Seq.iter( fun x -> list.Append( new PyFloat(x)))
        list

    //Worth making some convenience functions (see below for why)
    let a2 = np?array( [|1.0;2.0;3.0|] |> SeqToPyFloat )

    //--------------------
    //Problematic cases: these run but don't give good results
    //make a np.array from a generic list
    let list2 = [|1;2;3|] |> ResizeArray
    let c = np?array( list2 )
    printfn "%A" c //gives type not value in debugger

    //make a np.array from an array
    let d = np?array( [|1;2;3|] )
    printfn "%A" d //gives type not value in debugger

    //use a np.array in a function
    let sumD = np?sum(d)  //gives type not value in debugger
    //let sumCD = np?add(d,d) // this will crash

    //can't use primitive f# operators on the np.arrays without throwing an exception; seems 
    //to work in c# https://github.com/tonyroberts/pythonnet //develop branch
    //let e = d + 1

    //-----
    //NLTK
    //import nltk
    let nltk = Py.Import("nltk")
    let sentence = "I am happy"
    let tokens = nltk?word_tokenize(sentence)
    let tags = nltk?pos_tag(tokens)

    let taggedWords = nltk?corpus?brown?tagged_words()
    let taggedWordsNews = nltk?corpus?brown?tagged_words(Py.kw("categories", "news") )
    printfn "%A" taggedWordsNews

    let tlp = nltk?sem?logic?LogicParser(Py.kw("type_check",true))
    let parsed = tlp?parse("walk(angus)")
    printfn "%A" parsed?argument

    0 // return an integer exit code
@den-run-ai
Copy link
Contributor
den-run-ai commented Jan 31, 2016

This seems a better fit for pythonnet mailing list or a wiki page, since I do not see any issue, is there? I also copied your answer here:

http://stackoverflow.com/a/34207705/2230844

Folks from Deedle that is written in F# use pythonnet extensively.

@aolney
Copy link
Author
aolney commented Jan 31, 2016

Not issue in the sense of bug but perhaps in the broader sense https://guides.github.com/features/issues/

I'm not sure if there is an appropriate label that could be applied to this issue. It is not an enhancement per se but might be useful in future planning as another case study in dynamic.

Thanks for the Deedle/pythonnet connection

@royalstream
Copy link

The main problem I have with F# is not being able to use the standard arithmetic operators.
This is a limitation of the language, of course, not of Python.NET.

I resorted to this for the time being but needless to say it's not an optimal solution:

let (?+) a b = a?__add__(b)

The only other solution I can think of at this moment is forking pythonnet to define the respective static methods (e.g. op_Addition) in PyObject (so they become accessible from F#) and maybe using a custom ? operator that always returns a PyObject (as opposed to a raw obj)

@den-run-ai
Copy link
Contributor

Another way would be to submit a pull request to pythonnet with f# specific
code enabled using compilation symbol (like it is done now for various
platforms) or even runtime detection. Of course basic tests would be
welcome.

BTW, why F# uses special arithmetic operators?

On Friday, March 18, 2016, Steven notifications@github.com wrote:

The main problem I have with F# is not being able to use the standard
arithmetic operators.
This is a limitation of the language, of course, not of Python.NET.

I resorted to this for the time being but needless to say it's not an
optimal solution:

let (?+) a b = a?add(b)

The only other solution I can think of at this moment is forking
pythonnet to define the respective static methods (e.g. op_Addition)
in PyObject (so they become accessible from F#) and maybe using a
custom ? operator that always returns a PyObject (as opposed to a raw
obj)


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#112 (comment)

@royalstream
Copy link

It's actually the other way around: DynamicObject has direct support from the C# compiler, so the dot operator gets mapped to DynamicObject.TryInvokeMember/TryGetMember/etc and the arithmetic operators get mapped to DynamicObject.TryBinaryOperation/TryUnaryOperation/etc
F# has no such thing which is why you need to import the third party FSharp.Interop.Dynamic library so you can use the ? operator and for the time being there's no solution regarding the arithmetic operators.

@den-run-ai
Copy link
Contributor

@matthid did you encounter the issues above in your F# code with pythonnet? If yes, how did you workaround this?

@matthid
Copy link
Contributor
matthid commented Sep 5, 2016

I think @royalstream has said just about everything. There is no particular issue either on this (pythonnet) or the F# side. There is no (and probably wont be) dynamic support by the F# compiler.

I like the suggestion to add the operators at PyObject (eg op_addition).

@matthid
Copy link
Contributor
matthid commented Sep 5, 2016

I should note here that I immediately typed/casted/converted all results to static types. Therefore I did never notice this issue.

https://github.com/matthid/googleMusicAllAccess/blob/develop/src/GMusicApi/GMusicApi.fs#L176

https://github.com/matthid/googleMusicAllAccess/blob/develop/src/GMusicApi/PythonInterop.fs#L742

And I build a computation expression to not forget to gather and release the GIL: https://github.com/matthid/googleMusicAllAccess/blob/develop/src/GMusicApi/PythonInterop.fs#L20

More details: https://yaaf.de/blog/post/2016-05-28/Having%20Fun%20with%20Computation%20Expressions

@den-run-ai
Copy link
Contributor

@matthid thank you for the feedback, I included a link to your blog post in wiki:

https://github.com/pythonnet/pythonnet/wiki

BTW, congratulations on being featured in Microsoft weekly news!

https://blogs.msdn.microsoft.com/dotnet/2016/05/31/the-week-in-net-5312016/

@den-run-ai den-run-ai changed the title Using F# successfully Using F# (FSHARP) successfully Sep 9, 2016
@den-run-ai
Copy link
Contributor

@aolney I found your blog post as well (Using NLTK from F#) and linked it in wiki.

@dsyme
Copy link
dsyme commented Jun 21, 2017

As described below the most significant complaint is that you can't use F# primitive operators like (+) on numpy arrays without an error. The workaround is to use the corresponding numpy function as demonstrated.

It would make sense to track this with an F# language suggestion. But the techniques you are using today make sense.

@jbtule
Copy link
jbtule commented Aug 22, 2017

FSharp.Interop.Dynamic has operators now for dynamic objects. Version 4.0 (current beta package on nuget. )

open FSharp.Interop.Dynamic.Operators

https://github.com/fsprojects/FSharp.Interop.Dynamic/blob/1c7ce0551da8d864c174eb981cf52406ac506659/Tests/Library1.fs#L194-L229

@den-run-ai
Copy link
Contributor

some F# related issues: #574

@filmor filmor removed the decision label Jun 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants
0