I don't understand why I'm getting the error below:
> let x = "ABCDAACCECFG"|>Seq.sort|>Seq.groupBy (fun x->x);;
val x : seq<char * seq<char>>
> x;;
val it : seq<char * seq<char>> =
seq
[('A', seq ['A'; 'A'; 'A']); ('B', seq ['B']);
('C', seq ['C'; 'C'; 'C'; 'C']); ('D', seq ['D']); ...]
> (x|> Seq.head).GetType();;
val it : System.Type =
System.Tuple`2[System.Char,System.Collections.Generic.IEnumerable`1[System.Char]]
{Assembly = mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;
AssemblyQualifiedName = "System.Tuple`2[[System.Char, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerable`1[[System.Char, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
...
DeclaredProperties = [|Char Item1;
System.Collections.Generic.IEnumerable`1[System.Char] Item2;
Int32 System.ITuple.Size|];
...;}
> x|> Seq.map (fun x -> x.Item1, x.Item2)|>dict;;
x|> Seq.map (fun x -> x.Item1, x.Item2)|>dict;;
------------------------^^^^^
stdin(123,25): error FS0039: The field, constructor or member 'Item1' is not defined.
It appears to me that x is a sequence of tuples where each tuple has an Item1 (Char) and Item2 (seq Char) property. I'd like to turn this into a dictionary.
Clearly, I'm missing something. Can anyone help me understand what I'm doing wrong and how to get it right?
It doesn't appear that F# surfaces the Item1 and Item2 properties from the underlying tuple like in C#. I tried the following which appear to work without error.
Using functions fst and snd:
x|> Seq.map (fun x -> fst x, snd x) |> dict
Using pattern matching:
x|> Seq.map (function (key, value) -> (key, value)) |> dict
And apparently without using Seq.map works as well:
x |> dict
Related
I have a function that takes two lists and generates a Cartesian product.
let cartesian xs ys = xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
My problem is I am passing two lists of type Int64, and I am getting errors because the function is expecting two lists of type Int32.
How does one explicitly set the list type?
Adding a type annotation to one of the arguments should work:
let cartesian (xs: int64 list) ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
Alternatively, use inline to infer types at call site:
let inline cartesian xs ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x * y))
> cartesian [1;2;3] [1;2;3];;
val it : int list = [1; 2; 3; 2; 4; 6; 3; 6; 9]
> cartesian [1L;2L;3L] [1L;2L;3L];;
val it : int64 list = [1L; 2L; 3L; 2L; 4L; 6L; 3L; 6L; 9L]
Extended comment: A third alternative exists, factoring out the part of the code which introduces the constraint. Because the F# multiplication operator has the signature
val inline ( * ) : ^T1 -> ^T2 -> ^T3
when (^T1 or ^T2) : (static member (*) : ^T1 * ^T2 -> ^T3)
its static member constraint cannot be generalized unless the code in which it appears is marked inline. Move the operator to the call site:
let cartesian f xs ys =
List.collect (fun x -> List.map (f x) ys) xs
// val cartesian : f:('a -> 'b -> 'c) -> xs:'a list -> ys:'b list -> 'c list
cartesian (*) [1L..3L] [1L..3L]
// val it : int64 list = [1L; 2L; 3L; 2L; 4L; 6L; 3L; 6L; 9L]
[<ReflectedDefinition>]
module Foo =
let x = 5
let y () = 6
let z a = a
I tried to find out how to get the AST in this situation a couple of times now and keep failing. Time to ask the question here.
So far, I thought that a module would be mappped to a class with static members internally and as such, it should be the equivalent of:
[<ReflectedDefinition>]
type Foo =
static member x = 5
static member y () = 6
static member z a = a
let bar_members =
typeof<Bar>.GetMethods()
|> Array.filter (fun mi -> match mi with | MethodWithReflectedDefinition x -> true | _ -> false)
|> Array.map (fun m -> sprintf "%s: %A" (m.Name) (Expr.TryGetReflectedDefinition(m :> MethodBase) ) )
In the latter case, I could use typeof<Foo>.GetMembers() (or GetMethods()?!), cast it to Reflection.MethodBase and use this as an argument for Expr.TryGetReflectedDefinition().
But unfortunately, this is not working with the module version.
So, how to do it?
If you want to play with the code, you might want to open some namespaces:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Reflection
open System.Reflection
The problem comes go down to actually getting the type of the Module. In order to do that, there's a great answer here by Phillip Trelford: https://stackoverflow.com/a/14706890/5438433
Basically, you add a helper value to your module which returns the type of that module:
[<ReflectedDefinition>]
module Foo =
type internal IMarker = interface end
let fooType = typeof<IMarker>.DeclaringType
let x = 5
let y () = 6
let z a = a
You can then use fooType to retrieve the reflected definitions.
let foo_members =
Foo.fooType.GetMethods()
|> Array.filter (fun mi -> match mi with | MethodWithReflectedDefinition x -> true | _ -> false)
|> Array.map (fun m -> sprintf "%s: %A" (m.Name) (Expr.TryGetReflectedDefinition(m :> MethodBase) ) )
I can then, e.g. print the results:
[|"get_fooType: Some PropertyGet (Some (Call (None, TypeOf, [])), DeclaringType, [])";
"get_x: Some Value (5)";
"y: Some Lambda (unitVar0, Value (6))";
"z: Some Lambda (a, a)"|]
For the use case, when the reflected definitions are in another assembly (like an F# dll, for example), you can do without the marker interface trick, as shown below:
open System
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Reflection
open System.Reflection
open FSharp.Reflection.FSharpReflectionExtensions
let tryGetReflectedModules (a : Assembly) : seq<TypeInfo> =
a.DefinedTypes
|> Seq.filter
(fun dt ->
dt.CustomAttributes
|> Seq.map (fun cad -> cad.AttributeType)
|> Seq.filter ((=) (typeof<ReflectedDefinitionAttribute>))
|> Seq.isEmpty
|> not
)
let astFromReflectedDefinition (mi : MethodInfo) : Expr option =
mi :> MethodBase |> Expr.TryGetReflectedDefinition
let reflectedMethodsOfAModule (m : System.Type) : (MethodInfo * Expr) [] =
m.GetMethods()
|> Array.map (fun m -> (m,astFromReflectedDefinition m))
|> Array.filter (snd >> Option.isSome)
|> Array.map (fun (x,y) -> (x, Option.get y))
let reflectAssembly (assemblyPath : string) =
let a = System.Reflection.Assembly.LoadFile(assemblyPath)
a
|> tryGetReflectedModules
|> Seq.map (fun x -> (x,reflectedMethodsOfAModule (x.AsType())))
Where, for example, the assembly I used for testing the code above looked like this:
namespace Input
[<ReflectedDefinition>]
module Api =
let trace s =
for _ in [0..3] do System.Diagnostics.Trace.WriteLine s
[<ReflectedDefinition>]
module Foo =
let foobar (x : string) : string =
x.ToUpper()
You get the top level types in the assembly, which just so happen to be the (static) classes, representing the modules of the Fsharp assembly and test for the ReflectedDefinitionAttribute presence. Then, you take it from there.
The following code fails:
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations
let (empty,cons) =
FSharpType.GetUnionCases(typeof<List<_>>)
|> (fun cases ->
cases |> Array.find (fun c -> c.Name = "Empty"),
cases |> Array.find (fun c -> c.Name = "Cons"))
let valuesToList values =
values
|> List.map (fun v -> Expr.Value(v))
|> List.fold
(fun l v -> Expr.NewUnionCase(cons, [v;l]))
<## List.empty<int> ##>
[1;2;3]
|> valuesToList
with the exception:
System.ArgumentException: Type mismatch when building 'sum': incorrect argument type for an F# union. Expected 'System.Object', but received type 'System.Int32'.
How do I specify the generic parameter type of the Cons union case?
The problem is with GetUnionCases(typeof<List<_>>). The wildcard is being inferred as obj. Thus the error
Expected 'System.Object', but received type 'System.Int32'.
Here's a working version.
let valuesToList (values: list<'a>) =
let empty, cons =
FSharpType.GetUnionCases(values.GetType())
|> (fun cases ->
cases |> Array.find (fun c -> c.Name = "Empty"),
cases |> Array.find (fun c -> c.Name = "Cons"))
values
|> List.map Expr.Value
|> List.fold
(fun l v -> Expr.NewUnionCase(cons, [v;l]))
<## List.empty<'a> ##>
I'm having problems getting an interface with type constraints to work generically.
Here's the type
type LeftistHeap<'a when 'a : comparison> =
...
interface IHeap<LeftistHeap<'a>, 'a> with
...
member this.Insert (x : 'a) = LeftistHeap.insert x this
and the interface
type IHeap<'a when 'a : comparison> =
inherit System.Collections.IEnumerable
inherit System.Collections.Generic.IEnumerable<'a>
...
type IHeap<'c, 'a when 'c :> IHeap<'c, 'a> and 'a : comparison> =
inherit IHeap<'a>
...
abstract member Insert : 'a -> 'c
this code works no problem
let insertThruList l h =
List.fold (fun (h' : LeftistHeap<'a>) x -> h'.Insert x ) h l
but if I try to genralize the code for the interface
let insertThruList l h =
List.fold (fun (h' : IHeap<_,'a>) x -> h'.Insert x ) h l
I get this error at h'.Insert
Type mismatch. Expecting a
'b
but given a
IHeap<'b,'a>
The resulting type would be infinite when unifying ''b' and 'IHeap<'b,'a>'
The compiler's right: you're trying to use a 'c where you need an IHeap<'c,_>. Since 'c :> IHeap<'c,_>, one solution is just to insert an upcast:
let insertThruList l h =
List.fold (fun (h' : IHeap<_,_>) x -> h'.Insert x :> _) h l
Alternatively, you can indicate that you don't want the input to be (exactly) an IHeap<_,_>, but instead some particular subtype:
let insertThruList l h =
List.fold (fun (h' : #IHeap<_,_>) x -> h'.Insert x) h l
This is probably what you really want (the type is more specific). This is equivalent to the more verbose definition:
let insertThruList<'c,'a when 'a : comparison and 'c :> IHeap<'c,'a>> l h =
List.fold (fun (h' : 'c) x -> h'.Insert x) h l
will this work for your case?
let insertThruList l (h : 'T when 'T :> IHeap<'T, 'a> ) =
List.fold (fun (h' : 'T) x -> h'.Insert x ) h l
Let's say we have a simple F# quotation:
type Pet = { Name : string }
let exprNonGeneric = <## System.Func(fun (x : Pet) -> x.Name) ##>
The resulting quotation is like:
val exprNonGeneri : Expr =
NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],
x, PropertyGet (Some (x), System.String Name, []))
Now I want to generalize it, so I instead of type "Pet" and property "Name" I could use an arbitrary type and method/property defined on it. Here is what I am trying to do:
let exprGeneric<'T, 'R> f = <## System.Func<'T, 'R>( %f ) ##>
let exprSpecialized = exprGeneric<Pet, string> <# (fun (x : Pet) -> x.Name) #>
The resulting expression is now different:
val exprSpecialized : Expr =
NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],
delegateArg,
Application (Lambda (x,
PropertyGet (Some (x), System.String Name, [])),
delegateArg))
As you can see, the difference between the first and the second expression is that in first case the top level NewDelegate expression contains PropertyGet, while the second expression wraps PropertyGet in a Application/Lambda expression. And when I pass this expression to an external code it does not expect such expression structure and fails.
So I need some way to build a generalized version of quotation, so when it gets specialized, the resulting quotation is an exact match of <## System.Func(fun (x : Pet) -> x.Name) ##>. Is this possible? Or it there only choice to manually apply pattern matching to a generated quotation and transform it to what I need?
UPDATE. As a workaround I implemented the following adapter:
let convertExpr (expr : Expr) =
match expr with
| NewDelegate(t, darg, appl) ->
match (darg, appl) with
| (delegateArg, appl) ->
match appl with
| Application(l, ldarg) ->
match (l, ldarg) with
| (Lambda(x, f), delegateArg) ->
Expr.NewDelegate(t, [x], f)
| _ -> expr
| _ -> expr
| _ -> expr
It does the job - I can now convert expression from 1st to 2nd form. But I am interested in finding out if this can be achieved in a simple way, without traversing expression trees.
I don't think it will be possible to do this; in the second case, you are plugging in the expression <# (fun (x : Pet) -> x.Name) #>, which is represented using a Lambda node, into the hole in the other expression. The compiler does not simplify expressions during this plugging process, so the Lambda node won't be removed no matter what you do.
However your pattern matching workaround can be greatly simplified:
let convertExpr = function
| NewDelegate(t, [darg], Application(Lambda(x,f), Var(arg)))
when darg = arg -> Expr.NewDelegate(t, [x], f)
| expr -> expr
In fact, your more complicated version is incorrect. This is because the delegateArg in your innermost pattern is not matching against the value of the previously bound delegateArg identifier from the outer pattern; it is a new, freshly bound identifier which also happens to be called delegateArg. In fact, the outer delegateArg identifier has type Var list while the inner one has type Expr! However, given the limited range of expression forms generated by the compiler your broken version may not be problematic in practice.
EDIT
Regarding your followup questions, if I understand you correctly it may not be possible to achieve what you want. Unlike C#, where x => x + 1 could be interpreted as having a type of either Func<int,int> or Expression<Func<int,int>>, in F# fun x -> x + 1 is always of type int->int. If you want to get a value of type Expr<int->int> then you generally need to use the quotation operator (<# #>).
There is one alternative that may be of use, however. You can use the [<ReflectedDefinition>] attribute on let bound functions to make their quotations available as well. Here's an example:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.ExprShape
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns
let rec exprMap (|P|_|) = function
| P(e) -> e
| ShapeVar(v) -> Expr.Var v
| ShapeLambda(v,e) -> Expr.Lambda(v, exprMap (|P|_|) e)
| ShapeCombination(o,l) -> RebuildShapeCombination(o, l |> List.map (exprMap (|P|_|)))
let replaceDefn = function
| Call(None,MethodWithReflectedDefinition(e),args)
-> Some(Expr.Applications(e, [args]))
| _ -> None
(* plugs all definitions into an expression *)
let plugDefs e = exprMap replaceDefn e
[<ReflectedDefinition>]
let f x = x + 1
(* inlines f into the quotation since it uses the [<ReflectedDefinition>] attribute *)
let example = plugDefs <# fun y z -> (f y) - (f 2) #>