Namespace not found in F# fsx - f#

I've searched around for this but nobody seems to be having quite the same issue with F# .fsx scripts not finding namespaces. I've got Common project that builds fine and is picked up by intellisense in another project but the script in that same project proclaims it as not defined even though hovering over the #r "Common.dll" finds the full path. The common code:
namespace Common
open System
open System.Text
open System.Security.Cryptography
module Guid =
let swapBytes (a: byte[]) =
Array.concat [ Array.rev a.[..3] ; Array.rev a.[4..5] ; Array.rev a.[6..7]; a.[8..15] ]
// Implementaion of http://www.ietf.org/rfc/rfc4122.txt section 4.3 version 5 (Name Based using SHA-1)
// Based on C# at https://github.com/LogosBible/Logos.Utility/blob/master/src/Logos.Utility/GuidUtility.cs
type System.Guid with
static member FromName (guid:System.Guid) (name:string) =
let nameBytes: byte[] = Encoding.UTF8.GetBytes name
let nameSpaceBytes = guid.ToByteArray() |> swapBytes
use algorithm = SHA1.Create()
algorithm.TransformBlock (nameSpaceBytes, 0, nameSpaceBytes.Length, null, 0) |> ignore
algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length) |> ignore
let hash = algorithm.Hash;
let newGuid = Array.create 16 0uy
Array.Copy(hash, 0, newGuid, 0, 16)
Array.set newGuid 6 ((newGuid.[6] &&& 0x0Fuy) ||| (5uy <<< 4))
Array.set newGuid 8 ((newGuid.[8] &&& 0x3Fuy) ||| 0x80uy)
newGuid |> swapBytes |> System.Guid
The .fsx content:
#I #"..\Common\bin\Debug"
#r "Common.dll"
open Common
let NamedGuid = System.Guid.FromName (Guid("190bbe82-5692-43a4-b825-079f41fc55c0"))
This is in VS2015. What is missing?

You need to open the Guid module as well, or annotate it with the [<AutoOpen>] attribute. This will resolve the reference to System.Guid.FromName.
And after you do that, you will also need to open the System namespace in order to access the Guid constructor (or call System.Guid directly).

Related

Deserializing to enum option in F#

A couple days ago, I posted a question about deserialization with enums in F#.
The question is here: Deserialization in F# vs. C#
The answer pointed to some code written by Isaac Abraham, at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e
However I am facing another problem:
If the object to deserialize to has an object of type 'enum option', the deserialization will fail, whereas it'll work if the type is just 'enum'.
A minimal example:
type TestType =
| A = 0
| B = 1
type TestObjectA =
{
test : TestType
}
type TestObjectB =
{
test : TestType option
}
let x = "{\"test\":\"A\"}"
let TestA = Deserialize<TestObjectA> x // will work
let TestB = Deserialize<TestObjectB> x // will fail
and the large deserialization code is at: https://pastebin.com/95JZLa6j
I put the whole code in a fiddle: https://dotnetfiddle.net/0Vc0Rh
but it can't be run from there since the F# version they support will not accept the 'object' keyword.
So, my question is: why can't I use the option type on an enum, but it works on other types? As a side note, since I'm quite new to F#, I'm not fully understanding Isaac's code, although I spent some time going through it and trying to troubleshoot it.
My understanding is that this line:
|> Seq.map (fun (value, propertyInfo) -> Convert.ChangeType(value, propertyInfo.PropertyType))
will try to convert the type to the right enum, but not to the enum option.
As a bonus question, is there a working solution that does full idiomatic deserialization with enums? (without going through null types)
open System.IO
type TestType =
| A = 0
| B = 1
type TestObjectB =
{
test : TestType option
}
let jsonSerializeToString obj =
use writer = new StringWriter()
let ser = new Newtonsoft.Json.JsonSerializer()
ser.Formatting <- Newtonsoft.Json.Formatting.Indented
ser.Serialize(writer, obj)
writer.ToString()
let jsonDeserializeFromString str =
Newtonsoft.Json.JsonConvert.DeserializeObject<TestObjectB>(str)
let Test obj =
let str = jsonSerializeToString obj
let obj' = jsonDeserializeFromString str
obj'
[<EntryPoint>]
let main argv =
{ test = Some TestType.B } |> Test |> ignore
{ test = None } |> Test |> ignore
0
Note: if you need to serialize a large collection of objects, then stream them to a file instead of an in-memory string to avoid an OutOfMemoryException. Like use writer = File.CreateText(filePath).
As a bonus question, is there a working solution that does full
idiomatic deserialization with enums?
I use the Microsoft.FsharpLu.Json package in production and find it works quite well for serializing and deserializing between "plain" javascript and idiomatic F#. Note Microsoft.FsharpLu.Json relies on Newtonsoft.Json under the hood.
Below is an example with your types and your test string, using Expecto for tests.
namespace FsharpLuJsonTest
open Newtonsoft.Json
open Microsoft.FSharpLu.Json
open Expecto
open Expecto.Flip
// Setup for FSharpLu.Json
type JsonSettings =
static member settings =
let s = JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore)
s.Converters.Add(CompactUnionJsonConverter())
s
static member formatting = Formatting.None
type JsonSerializer = With<JsonSettings>
// Your example
type TestType =
| A = 0
| B = 1
type TestObjectA = { test : TestType }
type TestObjectB = { test : TestType option }
module Tests =
let x = """{"test":"A"}"""
[<Tests>]
let tests =
testList "Deserialization Tests" [
testCase "To TestObjectA" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectA.test = TestType.A }
testCase "To TestObjectB" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectB.test = Some TestType.A }
]
module Main =
[<EntryPoint>]
let main args =
runTestsInAssembly defaultConfig args
As you can see FsharpLu.Json supports Discriminated Unions and option types out of the box in the way you prefer. FsharpLu.Json is a less flexible solution than some others like Chiron (which allow for much more customisation) but I tend to prefer the opinionated approach of FsharpLu.Json.
I haven't used it personally, but the new FSharp.SystemText.Json library with the JsonUnionEncoding.ExternalTag setting should work roughly the same way FsharpLu.Json does. That library uses Microsoft's new System.Text.Json library under the hood rather than Newtonsoft.Json.

F# - How to call Moq ReturnsAsync()?

I have a function that returns Task<bool> (C#).
Task<bool> Update(MemberMarketUpdate memberMarketUpdate);
I'm trying to mock it using Moq (F#).
let verifyUpdate(update:MemberMarketUpdate) =
update.Id |> should equal "market id"
let setup = associationRepository.Setup (fun r -> r.Update(It.IsAny<MemberMarketUpdate>() ))
setup.Callback(fun update -> verifyUpdate update) |> ignore
//setup.Returns(Task.FromResult(True)) <- does not compile
//setup.ReturnsAsync(True) <- does not compile
I'm not able to use ReturnsAsync(True) to mock the Task<bool> result.
The error says:
No overloads match for method ReturnsAsync. The available overloads
are shown below.
(35 overloads here)
What is the correct syntax?
I tried to get your code to type check in a simple F# script file and the only thing I had to do to make it work was to change your upper-case True to lower-case true.
My complete script that type-checks fine, including all the necessary definitions and references looks like this:
#r #"packages\Moq\lib\net45\Moq.dll"
#r #"packages\NUnit\lib\net45\nunit.framework.dll"
#r #"packages\FsUnit\lib\net46\FsUnit.NUnit.dll"
#r #"packages\System.Threading.Tasks.Extensions\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll"
open Moq
open FsUnit
open System.Threading.Tasks
type MemberMarketUpdate =
{ Id: string }
type IAssociationRepository =
abstract Update : MemberMarketUpdate -> Task<bool>
let verifyUpdate(update:MemberMarketUpdate) =
update.Id |> should equal "market id"
let associationRepository = new Mock<IAssociationRepository>();
let setup = associationRepository.Setup (fun r -> r.Update(It.IsAny<MemberMarketUpdate>() ))
setup.Callback(fun update -> verifyUpdate update) |> ignore
setup.Returns(Task.FromResult(true))
setup.ReturnsAsync(true)
I am not that familiar with f# but try it all in one fluent call like the following, if possible.
associationRepository
.Setup(fun r -> r.Update(It.IsAny<MemberMarketUpdate>()))
.Callback(fun update -> verifyUpdate update)
.ReturnsAsync(True) |> ignore

Websharper compiler can't translate other assemblies

my goal is to simply output a javascript file containing my translated F# library. Nothing more.
I have an empty solution to which I added two F# projects. One is a library called WSLib with a single file:
namespace WSLib
[<ReflectedDefinition>]
type Class1() =
member this.X = "F#"
[<ReflectedDefinition>]
module Foo =
let bar = 34
The other project is a console app and references the WebSharper and WebSharper.Compiler NuGet packages. It has a single file. I copied the first half of the code from http://www.fssnip.net/snippet/rP.
module Program
open Microsoft.FSharp.Quotations
open WebSharper
type AR = IntelliFactory.Core.AssemblyResolution.AssemblyResolver
module FE = WebSharper.Compiler.FrontEnd
let compile (expr: Expr) : string option =
let loader = FE.Loader.Create (AR.Create()) (eprintfn "%O")
let options =
{ FE.Options.Default with
References =
List.map loader.LoadFile [
// These contain the JavaScript implementation for most of the standard library
"WebSharper.Main.dll"
"WebSharper.Collections.dll"
"WebSharper.Control.dll"
"WSLib.dll"
// Add any other assemblies used in the quotation...
] }
let compiler = FE.Prepare options (sprintf "%A" >> System.Diagnostics.Debug.WriteLine)
compiler.Compile expr
|> Option.map (fun e -> e.ReadableJavaScript)
[<JavaScript>]
let main() =
let a = WSLib.Class1().X
let b = WSLib.Foo.bar
(a,b)
let code =
match (compile <# main() #>) with
|None -> failwith "parse failed"
|Some x -> x
open System.IO
let filePath = Path.Combine(System.Environment.CurrentDirectory, "index.js")
File.WriteAllText(filePath, code)
I get a couple of errors:
{Location = {ReadableLocation = "main";
SourceLocation = null;};
Priority = Error;
Text = "Failed to translate property access: X [WSLib.Class1].";}
{Location = {ReadableLocation = "main";
SourceLocation = null;};
Priority = Error;
Text = "Failed to translate property access: bar [WSLib.Foo].";}
What do I need to do to get the websharper compiler working with different projects? I get the same error if I include the WebSharper package on WSLib and replace ReflectedDefinition with JavaScript.
What happens here is that adding WSLib.dll to the compiler references will only make it look for WebSharper metadata in that assembly, if there is any; but WSLib needs to be WebSharper-compiled already. For this to happen, you need to reference WebSharper in WSLib (as you did) and add the following property to the project file:
<WebSharperProject>Library</WebSharperProject>
to instruct WebSharper that it does have to compile this assembly.

FsCheck DataGen is null

I'm trying to work through an example of FsCheck right now for a type with discriminated unions in order to establish best practices for our larger project. Right now I am getting null from my generator and I am not sure why. In the following code, DataGen.containerGenerator is null.
namespace Container
open System
open Xunit
open FsCheck
module ContainerLibrary =
type [<Measure>] oz
type Container =
| Cup of Common
| Bowl of Common
and Common =
{ Volume :decimal<oz>
Weight :decimal}
module DataGen =
type Generators =
static member arbVolume =
FsCheck.Gen.choose (1, 16)
|> FsCheck.Gen.map(fun x -> (decimal x / 8.0M) * 1.0M<ContainerLibrary.oz>)
|> FsCheck.Arb.fromGen
FsCheck.Arb.register<Generators>() |> ignore
let bowlGenerator =
FsCheck.Gen.map2 (fun a b -> ContainerLibrary.Bowl( { Volume = a
Weight = b}))
(Generators.arbVolume.Generator)
(FsCheck.Arb.generate<decimal>)
let cupGenerator =
FsCheck.Gen.map2 (fun a b -> ContainerLibrary.Cup( { Volume = a
Weight = b}))
(Generators.arbVolume.Generator)
(FsCheck.Arb.generate<decimal>)
let containerGenerator =
Gen.oneof [bowlGenerator; cupGenerator]
module Tests =
[<Fact;>]
let ``01 : Containers must be no more than 20 oz`` () =
//Is this the best way to get one of something?
let c = FsCheck.Gen.sample 0 1 DataGen.containerGenerator |> Seq.head
Assert.NotNull (c)
It doesn't seem to be null when I run it, even when I get more values. Which version of FsCheck are you using?
[<Fact;>]
let ``01 : Containers must be no more than 20 oz`` () =
//Is this the best way to get one of something?
Gen.sample 0 100 DataGen.containerGenerator |> Seq.iter(fun c -> printf "%A" c; Assert.NotNull (c))
In any case, there are several things to note about what you're doing.
FsCheck uses reflection to register generators; and type of measure type parameters cannot be seen by reflection. So the Arb.register would actually override the decimal generator, for all decimals.
Somehow the FsCheck. qualifications you used confused intellisense no end.
Gen.sample is a reasonable way to test generators but I mostly use it in interactive settings; if you've gone through the trouble of setting up a test I tend to use FsCheck's built in test-case observation capabilities. See "Observing test case distribution" here: https://fsharp.github.io/FsCheck/Properties.html
Using Arb.register in the module init like you're doing is a bit brittle, depending on module initialization rules in F# to register generators. If you're using Xunit, it's much better to use the built-in integration to reduce inevitable frustration in this area.
I've rewritten your example a bit taking some of these things into account:
module DataGen =
open ContainerLibrary
//can't really register this one because of the measure, would override all decimal generatos
let volumeGenerator =
Gen.choose (1, 16)
|> Gen.map(fun x -> (decimal x / 8.0M) * 1.0M<ContainerLibrary.oz>)
let commonGenerator =
Gen.map2 (fun a b -> { Volume = a
Weight = b})
(volumeGenerator)
(Arb.generate<decimal>)
//in case you like applicative style, otherwise completely equivalent
let commonGeneratorAlternative =
(fun a b -> { Volume = a; Weight = b}) <!> volumeGenerator <*> Arb.generate<decimal>
let bowlGenerator = Gen.map Bowl commonGenerator
let cupGenerator = Gen.map Cup commonGenerator
let containerGenerator =
Gen.oneof [bowlGenerator; cupGenerator]
type Generators =
static member Container() = containerGenerator |> Arb.fromGen
module Tests =
open FsCheck.Xunit
open ContainerLibrary
//use PropertyAttribute from FsCheck.Xunit
//use the defined container generator - can also move this to module level
//other ways to parametrize
[<Property(Arbitrary=[|typeof<DataGen.Generators>|])>]
//thanks to PropertyAttribute can now just take container as argument
let ``01 : Containers must be no more than 20 oz`` (container:Container) =
match container with
| Cup common
| Bowl common -> common.Volume <= 20.0M<oz>
|> Prop.collect container //see the generated values in the output
This outputs something like:
Ok, passed 100 tests.
1% Cup {Volume = 2.0M;
Weight = -0.0000221360928858744815609M;}.
1% Cup {Volume = 1.8750M;
Weight = 922337.20325598085121M;}.
etc

Is it possible to create an object expression at runtime? [duplicate]

How do I execute F# code from a string in a compiled F# program?
Here's a little script that uses the FSharp CodeDom to compile a string into an assembly and dynamically load it into the script session.
It uses a type extension simply to allow useful defaults on the arguments (hopefully let bound functions will support optional, named and params arguments in the near future.)
#r "FSharp.Compiler.dll"
#r "FSharp.Compiler.CodeDom.dll"
open System
open System.IO
open System.CodeDom.Compiler
open Microsoft.FSharp.Compiler.CodeDom
let CompileFSharpString(str, assemblies, output) =
use pro = new FSharpCodeProvider()
let opt = CompilerParameters(assemblies, output)
let res = pro.CompileAssemblyFromSource( opt, [|str|] )
if res.Errors.Count = 0 then
Some(FileInfo(res.PathToAssembly))
else None
let (++) v1 v2 = Path.Combine(v1, v2)
let defaultAsms = [|"System.dll"; "FSharp.Core.dll"; "FSharp.Powerpack.dll"|]
let randomFile() = __SOURCE_DIRECTORY__ ++ Path.GetRandomFileName() + ".dll"
type System.CodeDom.Compiler.CodeCompiler with
static member CompileFSharpString (str, ?assemblies, ?output) =
let assemblies = defaultArg assemblies defaultAsms
let output = defaultArg output (randomFile())
CompileFSharpString(str, assemblies, output)
// Our set of library functions.
let library = "
module Temp.Main
let f(x,y) = sin x + cos y
"
// Create the assembly
let fileinfo = CodeCompiler.CompileFSharpString(library)
// Import metadata into the FSharp typechecker
#r "0lb3lphm.del.dll"
let a = Temp.Main.f(0.5 * Math.PI, 0.0) // val a : float = 2.0
// Purely reflective invocation of the function.
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
let mth = asm.GetType("Temp.Main").GetMethod("f")
// Wrap weakly typed function with strong typing.
let f(x,y) = mth.Invoke(null, [|box (x:float); box (y:float)|]) :?> float
let b = f (0.5 * Math.PI, 0.0) // val b : float = 2.0
To use this in a compiled program you would need the purely reflective invocation.
Of course this is a toy compared to a full scripting API that many of us in the community have urgently requested.
best of luck,
Danny
Are you looking for an Eval function?
You might want to try looking at this blog post:
http://fsharpnews.blogspot.com/2007/02/symbolic-manipulation.html
If you read in your expressions into these kind of symbolic datastructures, they are pretty easy to evaluate.
Or, perhaps you are looking for scripting support:
http://blogs.msdn.com/chrsmith/archive/2008/09/12/scripting-in-f.aspx
If you really want dynamic compilation, you could do it with the F# CodeDom provider.
There has been movement on this front. You can now compile using the FSharp.Compiler.Service
simple sample using FSharp.Compiler.Service 5.0.0 from NuGet
open Microsoft.FSharp.Compiler.SimpleSourceCodeServices
let compile (codeText:string) =
let scs = SimpleSourceCodeServices()
let src,dllPath =
let fn = Path.GetTempFileName()
let fn2 = Path.ChangeExtension(fn, ".fs")
let fn3 = Path.ChangeExtension(fn, ".dll")
fn2,fn3
File.WriteAllText(src,codeText)
let errors, exitCode = scs.Compile [| "fsc.exe"; "-o"; dllPath; "-a";src; "-r"; "WindowsBase"; "-r" ;"PresentationCore"; "-r"; "PresentationFramework" |]
match errors,exitCode with
| [| |],0 -> Some dllPath
| _ ->
(errors,exitCode).Dump("Compilation failed")
File.Delete src
File.Delete dllPath
None
then it's a matter of Assembly.LoadFrom(dllPath) to get it into the current app domain.
followed by reflection based-calls into the dll (or possibly Activator.CreateInstance)
Sample LinqPad Usage

Resources