In Haskell I can use the quasiquoter to produce a custom AST using concrete syntax defined by custom parser, as described here: https://wiki.haskell.org/Quasiquotation
Is this possible in F#?
The closest thing I can think of is F#'s TypeProviders.
It allows provider code to be part of the compiler pipeline, and constructs types to be injected.
For example, there's the XML type provider:
type Author = XmlProvider<"""<author name="Paul Feyerabend" born="1924" />""">
let sample = Author.Parse("""<author name="Karl Popper" born="1902" />""")
printfn "%s (%d)" sample.Name sample.Born
For more, see the FSharp.Data project.
Related
(previously "using type provider from C#")
This should be easy to answer, and the underlying issue has be asked before, but I'm slightly confused about it, having dug into it, there's something I'm missing.
The Xml type provider in
https://fsharp.github.io/FSharp.Data/library/XmlProvider.html
is erased?
so the types in it can't be used from another assembly?
"Erasing Type Providers produce types that can only be consumed in the assembly or project they are generated from" (says the MS docs).
but if I define in one assembly this
module Xml
type Xml = FSharp.Data.XmlProvider<"""
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>""">
let foo () = Xml.Parse ("")
and in another assembly, reference the above assembly and go...
let x = Xml.foo ()
let s = x.From
this compiles...so if the MS docs are correct, the provider must be generative?
if I implement the same code in C#,
var x = Xml.foo();
var y = x.From;
then this code doesnt compiler
'XmlElement' does not contain a definition for 'From' and no accessible extension method 'From' accepting a first argument of type 'XmlElement'
which seems to imply its erased...or I need to do something else (I've included the same dependencies).
My hunch is its erased, but then how does the F# assembly compile?
(I want it to be generative to use from C# and VB).
As far as I can tell by looking at the source code, all the types provided by FSharp.Data are erased.
The XmlProvider type is defined by this line at https://github.com/fsharp/FSharp.Data/blob/master/src/Xml/XmlProvider.fs#L26
let xmlProvTy = ProvidedTypeDefinition(asm, ns, "XmlProvider", None, hideObjectMethods=true, nonNullable=true)
As you can see, the instantiation of the ProvidedTypeDefinition type does not include isErased=false.
The ProvidedTypeDefinition type has two constructors. See the signatures at https://github.com/fsprojects/FSharp.TypeProviders.SDK/blob/master/src/ProvidedTypes.fsi#L268-L275
Both constructors have an implementation including this line, which means that the provide type is erased by default:
let isErased = defaultArg isErased true
Without redesigning the XmlProvider, the only way you can consume it from C# is to wrap it in an F# class that exposes C#-friendly types. Not sure if that would result in a better design than just avoiding the type provider altogether.
Assuming by "erased" you mean being removed from the FSharp.Data Library? then XMLProvider its probably not removed from it because I just tried your code and it works in F# project (as you have also noticed).
Now about the C# project the thing is TypeProviders are a Fsharp specific thing, whatever magic F# compiler is doing to type check xml and access the From xml-node here is probably only exclusive to F#.
The type of you variable x here is FSharp.Data.Runtime.BaseTypes.XmlElement, looking at the documentation here and the source code here.
There doesn't seem to be any way of accessing the xml nodes in an OOP way. Its probably not meant to be accessed that way either. If you want to parse xml and read its nodes in C# there are plenty of other ways for that. One being XmlReader in System.Xml
I am very new to F# and I started to write my functional wrapper on top of OpenGL. I also intend to use it to write a graphics engine which should have interop with all .Net languages.
But it is hard to find information about which code constructs in F# are not CLS compliant.
For example I already know of a few that are not CLS compliant:
static type constrains
tupleless functions
probably 'T list and Seq
maybe even union types
How do I know what features of F# are not CLS compliant?
Use the CLSCompliant attribute. It will guarantee that your code is CLS-Compliant at compile time.
Like this:
module myProject.AssemblyInfo
open System
[<assembly: CLSCompliant(true)>]
do()
Source: Mike-Ward.Net: Learning F#–Assembly Level Attributes
For a more complete discussion of the CLSCompliant attribute, see C# Corner: Making Your Code CLS Compliant
If one uses the F# Interactive Shell (FSI), the inferred expression type (signature) is printed to the console along with its value:
val it : int * string * float = (42, "Hello F#", 42.0)
How can I mimick the same behaviour in my own code, e.g. to get the inferred types as string for a F# expression?
I don't need to dynamically evaluate any F# expressions, the expressions are known in compile time and are part of my (static) F# code. I need this feature to be able to mimick the FSI output in LINQPad for my F# demos.
Using Unquote
Unquote has a facility for getting the F# signature of a type. Simply download the latest release and add a reference through LINQPad to Unquote.dll, then you can do e.g.
If you're interested, you can peak at the source code for the implementation of the FSharpName Type extension: https://github.com/SwensenSoftware/unquote/blob/2.1.0/Unquote/ExtraReflection.fs#L54
Using FsEye
Another neat approach would be to use LINQPad's beta Custom Visualizer API to embed FsEye into LINQPad (FsEye uses the same F# type signature printing algorithm as Unquote). This is also very simple, all you need to do is download LINQPad beta, download and reference FsEye.dll from the latest release of FsEye, then you can do e.g.
If you look at the F# compiler code and see how the --sig option is handled by the compiler I think that will get you what you're looking for. More about the --sig option and signatures here:
Signatures (F#)
I'm fiddling with a new F# project (of which I haven't made many), and I'm aiming to do it in a TDD fashion. So, I'm trying to familiarize myself with using FsUnit, since I have a lot of experience using NUnit in C# projects, and it seems a pretty common framework to use.
My code looks like the following:
module DatabaseReaderTest
open NUnit.Framework
open FsUnit
[<TestFixture>]
type DatabaseReaderTest ()=
[<Test>]
member x.ResultsAreReturnedFromDatabase =
DatabaseReader.result.GetSqlString(1) |> should equal "first"
As far as I can tell, this follows the example on the FsUnit home page (http://fsunit.codeplex.com/), but the compiler tells me that [<Test>] is not a valid attribute on this language element, by which I assume it means member.
Any tips on what I'm doing wrong here?
Thanks!
You probably need to use a method rather than a property. Just add a () argument of type unit.
As a side-note, if you don't need any custom initialization before tests are run and if you're using a recent version of NUnit, then you should be able to use module with let bound functions for your tests.
This gives you a bit more lightweight syntax. Some people also like to use double-tick syntax that makes it possible to write the test name as an ordinary English sentence (which shows nicely in test runner):
module DatabaseReaderTest =
[<Test>]
let ``Results are returned from database`` () =
DatabaseReader.result.GetSqlString(1) |> should equal "first"
I'm trying to create a class and a method in it. For C# and VB, the CodeDom providers emit preditable output, but the F# CodeDom provider emits the following. I'm wondering why.
exception ReturnException8abef2fbb2404165b4b8690157bd3a49 of obj
exception ReturnNoneException8abef2fbb2404165b4b8690157bd3a49
type
// Hello
test = class
new() as this =
{
}
abstract my_method : unit -> unit
default this.my_method () =
()
end
Ignoring the exception stuff (I guess the provider is still a bit buggy), I'm curious as to why I get such a weird definition with new() as this, an abstract method and a default implementation. Am I missing something here?
The code generated by the CodeDOM generator is weird, but it is mostly valid F# code that compiles. As kvb points out, the definition of constructor is valid. It would be nicer if the CodeDOM provider generated code using implicit syntax, but that wouldn't work well if you had multiple constructors.
As for the exceptions, these are used to emulate imperative return construct (as in C#). For example, you cannot directly write the following in F#:
for(int i = 0; i < 10; i++)
if (i == 5) return;
So the CodeDOM generator uses exception to emulate return and try .. with to handle it.
The usual coding style in F# is simply a bit different from C#/VB and the CodeDOM data structures were designed mainly for C#/VB. If you want to generate nice F# code, then writing your own code generator may be a better idea. Alternatively, someone could create F# CodeDOM provider that wouldn't support all features, but would generate nice code.
This looks fine to me.
new() as this = {}
is just an empty default constructor, and the abstract method with default implementation is how you define a virtual method in F# (see section 8.14.2 of the spec).