Skip to content

Using F# (FSHARP) successfully #112

Open

Description

@aolney

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

Activity

  1. den-run-ai commented on Jan 31, 2016

    @den-run-ai
    Contributor

    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.

  2. aolney commented on Jan 31, 2016

    @aolney
    Author

    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

  3. royalstream commented on Mar 19, 2016

    @royalstream

    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)

  4. den-run-ai commented on Mar 19, 2016

    @den-run-ai
    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)

  5. royalstream commented on Mar 19, 2016

    @royalstream

    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.

  6. den-run-ai commented on Sep 4, 2016

    @den-run-ai
    Contributor

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

  7. matthid commented on Sep 5, 2016

    @matthid
    Contributor

    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).

  8. matthid commented on Sep 5, 2016

    @matthid
    Contributor
  9. den-run-ai commented on Sep 9, 2016

    @den-run-ai
    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/

  10. changed the title [-]Using F# successfully[/-] [+]Using F# (FSHARP) successfully[/+] on Sep 9, 2016
  11. den-run-ai commented on Sep 9, 2016

    @den-run-ai
    Contributor

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

  12. dsyme commented on Jun 21, 2017

    @dsyme

    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.

  13. jbtule commented on Aug 22, 2017

    @jbtule

    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

  14. den-run-ai commented on Dec 5, 2017

    @den-run-ai
    Contributor

    some F# related issues: #574

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions