Using F# (FSHARP) successfully · Issue #112 · pythonnet/pythonnet

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