Can I parse some F# code at run-time that reference types in my current assembly? - f#

Say I have the following type defined:
type Foo = { A: string; B: int }
I want a function parse, such that:
let myfoo = parse<Foo> "{A = \"foo\"; B = 5}"
gives me an instance of type Foo (or error).
Is this possible using FSharp.Compiler.Service?
UPDATE:
While there are other questions that address parsing of F# code, they don't address having references in the current assembly.

You can do this by referencing the current assembly from the hosted F# interactive - this only works if you are running this from a compiled program (which has assembly located on disk) and if your types are public, but it may do the trick in your case.
Given the usual setup documented on the Embedding F# Interactive page, you can do something like this:
module Program
type Test = { A:int; B:string }
// (omitted code to initialize the fsi service)
let fsiSession = FsiEvaluationSession.Create(...)
// Run #r command to reference the current assembly
let loc = System.Reflection.Assembly.GetExecutingAssembly().Location
fsiSession.EvalInteraction(sprintf "#r #\"%s\"" loc)
// Open the module or namespace containing your types
fsiSession.EvalInteraction("open Program")
// Evaluate code using the type and cast it back to our type
let value = fsiSession.EvalExpression("{A=0; B=\"hi\"}").Value.ReflectionValue :?> Test
printfn "%A" value

Related

Calling ES 3rd party script method from F# Fable

I'm trying to get Fable to compile the following code correctly but am unable to do so:
module AppView
#r "../../../node_modules/fable-core/Fable.Core.dll"
open Fable.Core
open Fable.Import.Browser
open Fable.Core.JsInterop
[<Import("default", from="../../../js/3rd/riot.js")>]
module riot_js =
let mount:((string*obj)->array<obj>) = jsNative
type App
(
tagName:string
,state
,store
) =
member public x.AppTag =
(riot_js?mount ("app", state))
// does not compile: The value or constructor 'riot_js' is not defined.
// (riot_js.mount ("app", state))
// compiles wrongly to: riot_js.mount(["app", this.state]);
Trying riot_js?mount would magically cause riot_js to not exist any more and trying riot_js.mount compiles into riot_js.mount(["app", this.state]);.
Mount does not take one argument but 2 but it either won't transpile or transpile wrong.
For now I have one of the strangest looking solutions:
[<Emit("riot_js")>]
let riot_js (x: int): obj = jsNative
...
((riot_js 1)?mount ("app", state))
This returns an array but again Fable does not let me take the first element in a "normal" way:
((riot_js 1)?mount ("app", state))?[0]
Gives me red on [ with error Unexpected symbol '[' in expression. Expected identifier, '(' or other token.
And
((riot_js 1)?mount ("app", state)).[0]
Gives red on everything with error The field, constructor or member 'Item' is not defined.
The following "works"
((riot_js 1)?mount ("app", state))?``0``
And is compiled to:
riot_js.mount("app", this.state)["0"];
Not the best result someone can get. I'll let this question sit for a while and set a bounty on it for a week or so before opening 2 issues with Fable.
The following seems to compile to the right ES and does not need the ? so it'll be strongly typed.
open Fable.Core.JsInterop
type Riotjs =
{
mount:(System.Func<string,obj,string []>)
}
let riot = (importAll<obj> "../js/3rd/riot.js") :?> Riotjs
let app = riot.mount.Invoke("app",(createObj []))
I set initial state to type obj but can use a strong typed application state as well.
ES generated is:
export var app = riot.mount("app", {});

F# How to use an interface in a separate module

So I have been doing research on interfaces on F#. I have found these 2 articles on it. The MSDN and F# for fun and profit But unfortunately they are only skin deep.
UPDATED
here is my module with my interfaces
//open statements omitted for brevity
module DrawingInterfaces =
///gets a string representation of the SVG code representation of the object
type IRepresentable_SVG =
abstract member getSVGRepresenation : unit -> string
//other interfaces omitted for brevity
Now within the same namespace and physical folder also I have this:
type lineSet (x1off,x2off,y1off,y2off,x1,x2,y1,y2,rot,rotOff,count) =
//tons of member vals omitted for brevity
member val x1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.getSVGRepresenation() =
let mutable svg = ""
let mutable currentx1 = x1Start
svg
This used to give me 2 errors, before I was using the __. notation for the member. The first error was on the interface line. And a second on the member line.
The errors were respectively:
The type 'IRepresentable_SVG' is not defined
This instance member needs a parameter to represent the object being invoked.
I was able to fix the first one by changing the file order. Thanks to John Palmer.
The second one is nearly fixed./
After using the __ . notation I was able to get rid of the second error. However, now a new error pops up when I try to use type members in my interface implementation.
let mutable currentx1 = x1Start
x1Start shows as not being defined. I need to be able to use values stored in my other members within my implementation.
Let's first make it work and then point to your problems. I define below 2 separate modules in 2 separate .fs files within the same namespace Example for interface definition in module Example.DrawingInterfacesand interface implementation in module Example.UseInterface and also a console app that will use the interface from third (implicit) module Program. In my project correspondent code files are in the following order: DefInterface.fs, UseInterface,fs, Program.fs (I also made few idiomatic styling changes and more brevity omissions)
File: DefInterface.fs
namespace Example
module DrawingInterfaces =
type IRepresentable_SVG =
abstract member GetSVGRepresenation : unit -> string
File: UseInterface.fs
namespace Example
module UseInterface =
type LineSet (x1) =
member val X1Start = x1 with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.GetSVGRepresenation() = "test" + " " + __.X1Start.ToString()
File: Program.fs
open Example
open System
[<EntryPoint>]
let main argv =
let lineSet = UseInterface.LineSet(5)
let example : DrawingInterfaces.IRepresentable_SVG = lineSet :> _
example.GetSVGRepresenation() |> printfn "%A"
lineSet.X1Start <- 10
example.GetSVGRepresenation() |> printfn "%A"
0
Compile, run and make sure it works.
Now to problems in your code:
first error message stems from the need to refer to the full implemented interface name in UseInterface.fs, which is Example.DrawingInterfaces.IRepresentable_SVG although as both modules belong to the same namespace the Example prefix may be omitted
second error message points to the need of using instance method in implementation class UseInterface.LineSet, which is achieved by prepending self-identifier __. to the method signature
Finally, notice the usage of your interface in Program.fs that imports namespace, provides module names for definition and implementation respectively, and also explicitly casts implementation LineSet to IRepresentable_SVG.
EDIT: I've added X1Start property to the original LineSet to show how it can be used from interface implementation per question author's request. Now self-id __. is more involved and probably using self. or even this. instead would make more sense.

How to compile a quotation into a public static method of a new type in F#

I am playing with type providers and I am trying to compile a quotation into a public static method of a new generated type. Here is what I have:
let CreateType<'i> name methodName quotation =
let assemblyName = new AssemblyName(Name = "tmpAssembly")
let assemblyBuilder =
System.AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave)
let filename = "tmpAssembly.dll"
let tmpModule = assemblyBuilder.DefineDynamicModule(filename,filename)
// create a new type builder
let typeBuilder =
tmpModule.DefineType(
name,
TypeAttributes.Public ||| TypeAttributes.Class,
null, // parentType
[|typeof<'i>|])
let attr = MethodAttributes.Public ||| MethodAttributes.HideBySig ||| MethodAttributes.Static
let methodImpl =
typeBuilder.DefineMethod(
methodName,
attr,
typeof<unit>, // todo
[||]) // todo
let il = methodImpl.GetILGenerator()
// compile quotation to method
typeBuilder.CreateType()
I know there is a .Compile() method but I think that's not what I need. Any ideas?
I haven't really played with the F# 3.0 release yet, but I think that you don't need to generate IL code yourself. The post by Keith explains that there are two types of type providers - generated that create a real .NET type (that exists in some library) and erased that create a fake type and then give the compiler an expression tree to be used in place of the calls to the fake type.
It seems to me that you're trying to implement generated type provider in a situation where erased type would be more appropriate. In the erased case, you should be just able to return the .NET Expression<..> type (not the F# quotation though, but you can use ToLinqExpression from PowerPack) and the F# compiler will compile that for you.
However, I haven't played with it yet, so I don't know what's the exact mechanism.

F# top level do binding

I have a file with a module with some routines that take parameters and return unit, these routines have side-effects. I noticed that when accessing these f# routines from c# they're actually properties of type unit and when I try to access 1 property, it runs all properties in the module.
From the F# documentation all top level do bindings are run on type initialization.
What is the preferred way to write functions that should not be run on type initialization but are also not associated with other state i.e. a class with functions and member variables?
Should I put these functions inside a type and just have no records in the type?
Code example:
namespace test_space
open System.Diagnostics;
module test =
let test_1 =
Debug.WriteLine ("One")
let test_2 =
Debug.WriteLine ("Two")
I'm running this code with C#:
static void Main (string [] args)
{
Object o;
o = test.test_2;
}
And the output is:
One
Two
The problem is you didn't create functions but value bindings. test_1 is a value. test_1() is a function of type unit -> unit. Make sure you put () after the function name.
I don't fully understand the scenario you're describing - F# functions declared in a module will generally appear as methods and values will appear as properties. The code that is executed when you first access module (type initialization) is the initialization of values.
If you write just:
module Foo =
let Operation () =
printfn "hello"
...then calling Operation will be a method and calling Foo.Operation() will run the side-effect. If you can post some code that behaves unexpectedly, then someone can explain it.
Anyway, if you want to be sure about the behavior, you can write operations as static members of a class:
type Foo =
static member Operation() =
printfn "hello"
Then you can be sure that F# will compile them as static members of a class in a predictable way.

why is the implementation of my abstract member not public

I've been struggling to get this to compile for about an hour. It must be something stupid. Can you spot it?
in my lib project:
namespace TravelerStuff
open System
type Traveler =
abstract GetData : unit -> unit
type public DeltaTraveler() =
interface Traveler with
member v.GetData () =
printf "hello"
and in my console test app:
[<EntryPoint>] let main _ =
let traveler = new TravelerStuff.DeltaTraveler()
traveler.GetData // this line won't compile: (The field, constructor or member 'GetData' is not defined)
As gradbot says, F# doesn't currently implicitly convert values to interfaces when searching for members. Also, F# only uses explicit interface implementation (as known from C#) and not implicit implementation where members are not only compiled as implementation of an interface, but also as ordinary (directly visible) members of the type.
Aside from casting, you can duplicate the member in the type definition:
type DeltaTraveler() =
member v.GetData () = printf "hello"
interface Traveler with
member v.GetData () = v.GetData()
Also, if you just want to implement an interface, but don't need to add any members, you can use F# object expressions (which are more lightweight):
let deltaTraveler() =
{ new Traveler with
member v.GetData () = printf "hello" }
// The function directly returns value of type 'Traveler'
let t = deltaTraveler()
t.GetData()
You need to upcast. F# currently won't do it for you in this situation.
(traveler :> TravelerStuff.Traveler).GetData()
// open the namespace to reduce typing.
open TravelerStuff
(traveler :> Traveler).GetData()
Snip from F# docs.
In many object-oriented languages,
upcasting is implicit; in F#, the
rules are slightly different.
Upcasting is applied automatically
when you pass arguments to methods on
an object type. However, for let-bound
functions in a module, upcasting is
not automatic, unless the parameter
type is declared as a flexible type.
For more information, see Flexible Types (F#).

Resources