in the unquote userguide there is an example given, which i don't understand:
// raisesWith : Expr -> (#exn -> Expr<bool>) -> unit
raisesWith<System.NullReferenceException> <# ("s":string).Length #> (fun e -> <# e.ToString() = null #>)
You can give a short explanation and another example ?
You can assert on the error, as in the following example
raisesWith<DivideByZeroException> <# 1/0 #> (fun e -> <# e.Message = "Attempted to divide by zero." #>)
Related
How can I define an exception like the following?
exception CustomExn<'TMessage> of 'TMessage list
Maybe you can just inherit from System.Exception?
type CustomExn<'TMessage> (message:'TMessage list) =
inherit System.Exception ()
let test =
try
raise (CustomExn["string"] )
with
| :? CustomExn<string> -> "CustomExn of string"
| :? CustomExn<int> -> "CustomExn of int"
| _ -> "Everything else"
Not sure it is possible with F# Exception Definitions according to specs (page 164-165)
This one also NOT A GOOD SOLUTION because try with will only catch ExceptionList<string> in this case so there is no good way to make it generic
type ExceptionList<'a>(msgList: 'a list) =
inherit Exception()
member __.MessageList = msgList
let mock() =
raise <| ExceptionList(["failed"])
try
mock() //raises ExceptionList<string>
with
//this catch block won't fire, because it is not generic, it is ExceptionList<obj>
| :? ExceptionList<_> as exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
The better way though: Result<'a,'b list>:
let mock'() =
if DateTime.Now.Ticks % 2L = 0L
then Ok()
else Error(["failed"])
let result = mock'()
match result with
| Ok _ -> printfn "Ok!"
| Error (msgList) ->
msgList
|> List.iter (printfn "%A")
Added There is a workaround with type loss:
type ExceptionList(msgList: obj list) =
inherit Exception()
member __.MessageList = msgList
// Here is F# exception definition
exception CustomException of ExceptionList
let failwithMany msgs =
raise <| CustomException (ExceptionList(msgs))
let mock() =
//zero type checking here
failwithMany[1;2;"a";[];"failed"]
try
mock()
with
// exnList is list of objects
| CustomException exnList ->
exnList.MessageList
|> List.iter (printfn "%A")
My question is this:
How can I splice the expressions from a list into a quotation when I don't know the number and types of those expressions at design time?
At the bottom I've included the full code for a type provider. (I've stripped the concept down to demonstrate the problem.) My issue occurs at these lines:
let func = ProvidedMethod((*...*), InvokeCode = fun args ->
<## let stringParts =
args
|> List.mapi (fun i arg ->
if paramTypes.[i] = typeof<int> then
sprintf "%i" (%%arg: int)...
On the lambda parameter arg, I get the following error:
error FS0446: The variable 'arg' is bound in a quotation but is used as part of a spliced expression. This is not permitted since it may escape its scope.``
I can't figure out how to write code such that I "extract" the parameter values when the numbers and types of the values are not known at provider-design time (although they will be known at compile time).
When I DO know of a parameter's existence and type at design time, I can do this:
printfn "%A" (%%args.[0]: int)
But I can't figure out how to get from the Expr list input to an obj list within the quotation.
Here's the full type provider code:
[<TypeProvider>]
type SillyProviderDefinition(config: TypeProviderConfig) as self =
inherit TypeProviderForNamespaces()
let sillyType = ProvidedTypeDefinition(THIS_ASSEMBLY, NAMESPACE, "SillyProvider", Some typeof<obj>)
do sillyType.DefineStaticParameters([ProvidedStaticParameter("argTypes", typeof<string>)], fun typeName args ->
let retType = ProvidedTypeDefinition(typeName, Some typeof<obj>)
let paramTypes =
(args.[0] :?> string).Split([|'|'|])
|> Array.map (function
| "int" -> typeof<int>
| "string" -> typeof<string>
| x -> failwithf "Invalid argType %A. Only string or int permitted" x)
let parameters =
paramTypes
|> Array.mapi (fun i p -> ProvidedParameter(sprintf "arg%i" i, p))
|> Array.toList
let func = ProvidedMethod("Stringify", parameters, typeof<string>, IsStaticMethod = true, InvokeCode = fun args ->
<## let stringParts =
args
|> List.mapi (fun i arg ->
if paramTypes.[i] = typeof<int> then
sprintf "%i" (%%arg: int)
elif paramTypes.[i] = typeof<string> then
(%%arg: string)
else
failwith "Unexpected arg type")
//printfn "%A" (%%args.[0]: int)
String.Join("", stringParts) ##>)
do retType.AddMember func
do sillyType.AddMember retType
retType)
do self.AddNamespace(NAMESPACE, [sillyType])
As a minimal example, let's say that we have list with types and a list with some quotations (in the context of type provider, you have the list of types and args is the list of quotations, possibly also containing the this instance):
open Microsoft.FSharp.Quotations
let tys = [ typeof<int>; typeof<string> ]
let args = [ Expr.Value(42); Expr.Value("test"); ]
We want to construct an expression that calls formatInt or formatString depending on the type and then concatenates all the formatted strings:
let formatInt (n:int) = string n
let formatString (s:string) = s
Now, it's important to distinguish what happens in the provided quoted code (quote-level) and in the ordinary code that is run to generate the quotation (code-level). At code-level, we iterate over all the types and quoted arguments and generate a list of quotations with calls to formatInt or formatString - those can be typed Expr<string> because they have the same type:
let formattedArgList =
[ for t, e in List.zip tys args ->
if t = typeof<int> then <# formatInt %%e #>
elif t = typeof<string> then <# formatString %%e #>
else failwith "!" ]
Now you can build a list expression by calling fold at code-level and using the list :: operator at the quote-level:
let listArgExpr =
formattedArgList
|> List.fold (fun state e -> <# %e::%state #>) <# [] #>
And now you can construct a quotation with quoted String.concat call:
<# String.concat "," %listArgExpr #>
How to assert on exception message in FsUnit? Something like this from NUnit:
[<Test>]
let ShouldThrowExceptionAndLog() =
Assert.That
((fun () -> Calculator.Calculate "-1"),
Throws.Exception.With.Property("Message").EqualTo("Negatives not allowed: -1"))
EDIT: I don't care about the exception itself, I'd like to test the exception MESSAGE.
AFAIK there is no out-of-the-box matcher to do what you want, but it's easy enough to create one yourself:
open NHamcrest
let throwAnyWithMessage m =
CustomMatcher<obj>(m,
fun f -> match f with
| :? (unit -> unit) as testFunc ->
try
testFunc()
false
with
| ex -> ex.Message = m
| _ -> false )
usage:
(fun () -> raise <| Exception("Foo") |> ignore) |> should throwAnyWithMessage "Foo" // pass
(fun () -> raise <| Exception("Bar") |> ignore) |> should throwAnyWithMessage "Foo" // fail
In a new console application, just pasting the following code leads to the exception "The parameter is not a recognized method name".
Does the following code work on your installation?
Joker: Do you know any reason why it would not work on mine?
// Learn more about F# at http://fsharp.net
// See the 'F# Tutorial' project for more help.
let somefunction1 arg = ()
let somefunction2 () = ()
open Quotations.DerivedPatterns
let test() =
let d = <# somefunction1() #>
let e = <# somefunction2() #>
match d with
| SpecificCall <# somefunction1() #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
match d with
| SpecificCall <# somefunction1 #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
match e with
| SpecificCall <# somefunction2() #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
//THIS FAILS HERE saying "The parameter is not a recognized method name"
match e with
| SpecificCall <# somefunction2 #> (a,b ,c) -> printfn "somefunction"
| _ -> printfn "something else"
[<EntryPoint>]
let main argv =
test()
printfn "%A" argv
0 // return an integer exit code
Looking at the definition of active pattern SpecificCall defined in the compiler I find:
[<CompiledName("SpecificCallPattern")>]
let (|SpecificCall|_|) templateParameter =
// Note: precomputation
match templateParameter with
| (Lambdas(_,Call(_,minfo1,_)) | Call(_,minfo1,_)) ->
let isg1 = minfo1.IsGenericMethod
let gmd = if isg1 then minfo1.GetGenericMethodDefinition() else null
// end-of-precomputation
(fun tm ->
match tm with
| Call(obj,minfo2,args)
#if FX_NO_REFLECTION_METADATA_TOKENS
when (minfo1.MethodHandle = minfo2.MethodHandle &&
#else
when (minfo1.MetadataToken = minfo2.MetadataToken &&
#endif
if isg1 then
minfo2.IsGenericMethod && gmd = minfo2.GetGenericMethodDefinition()
else
minfo1 = minfo2) ->
Some(obj,(minfo2.GetGenericArguments() |> Array.toList),args)
| _ -> None)
| _ ->
invalidArg "templateParameter" (SR.GetString(SR.QunrecognizedMethodCall))
Offhand, that looks okay to me... Is it possible that you've shadowed the original definition of var somehow? For instance, the following self-contained example works fine for me:
let var<'a>() = Unchecked.defaultof<'a>
match <# var<int>() #> with
| Quotations.DerivedPatterns.SpecificCall <# var #> (obj,_,[]) ->
printfn "var"
| _ -> printfn "something else"
I've spent a few hours trying to get to grips with F# Quotations, but I've come across a bit of a road block. My requirement is to take simple functions (just integers,+,-,/,*) out of a discriminated union type and generate an expression tree that will eventually be used to generate C code. I know this is possible using Quotations with 'direct' functions.
My problem is that the expression tree seems to terminate with a "Value", and I can't figure out how to traverse into that value.
My questions is
whether this is actually possible in this situation? or are there any other approaches that are worth considering.
type FuncType =
| A of (int -> int -> int)
| B
| C
[<ReflectedDefinition>]
let add x y = x + y
let myFunc1 = A (fun x y -> x + y )
let myFunc2 = A add
let thefunc expr =
match expr with
| A(x) ->
<# x #>
| _ ->
failwith "fail"
printfn "%A" (thefunc myFunc1) // prints "Value (<fun:myFunc1#14>)"
printfn "%A" (thefunc myFunc2) // prints "Value (<fun:myFunc2#15>)"
printfn "%A" <# fun x y -> x + y #> // generates usable expression tree
Quotations represent the F# code that was quoted syntactically. This means that if you write something like <# x #>, the quotation will contain just Value case specifying that you quoted something which has the specified value. (Variables are automatically replaced with values if the variable is defined outside of the quotation).
You can only get quotation of code that was explicitly quoted using <# .. #> or of a function that was marked as ReflectedDefinition and is referred to by name in a quotation (e.g. <# add #> but not for example let f = add in <# f #>).
To be able to do what your snippet suggests, you'll need to store quotations in your FuncType too (so that the lambda function that you write is also quoted and you can get its body). Something like:
type FuncType =
| A of Expr<int -> int -> int>
| B | C
[<ReflectedDefinition>]
let add x y = x + y
let myFunc1 = A <# fun x y -> x + y #>
let myFunc2 = A <# add #>
let thefunc expr =
match expr with
| A(x) -> x
| _ -> failwith "fail"
This should work for functions marked as ReflectedDefinition too. To extract the body of the function you need to add something like (you'll need to substitute arguments of the function for parameters, but this should give you some idea):
match expr with
| Lambdas(_, body) ->
match body with
| Call(_, mi, _) when Expr.TryGetReflectedDefinition(mi) <> None ->
let func = Expr.TryGetReflectedDefinition(mi)
match func with
| Some(Lambdas(_, body)) ->
// 'body' is the quotation of the body
| _ -> failwith "Not supported function"
| _ -> failwith "Not supported function"
| _ -> failwith "Not supported expression"