Given the following F# snippet:
type A(children: A list) =
member val P1 = ""
member val P2 = ""
member val Children = children
type B = {
F1:string
Children: B list
}
let rec f1 (a:A) =
{
F1 = a.P1
Children = a.Children |> List.map f1
}
let rec f2 (a:A) =
{|
F1 = a.P1
Children = a.Children |> List.map f2 //Error
|}
let a = A([A([A([])])])
f1 a
f2 a
////////////////////
Error FS0001 Type mismatch. Expecting a
'A -> 'a'
but given a
'A -> {| Children: 'a list; F1: string |}'
The types ''a' and '{| Children: 'a list; F1: string |}' cannot be unified.Active
The compiler complains in f2 but not in f1.
What would be the correct syntax for anonymous record (if it exists)?
There won't be a correct syntax, this is just impossible.
Think about what would be the return type of f2. Since it's a record with a field Children that is a list of the same record, it would look something like this:
{|
F1: string
Children: list<
{|
F1: string
Children: list<
{|
F1: string
Children: list<
...
>
|}
>
|}
>
|}
It's an infinite type. Such a beast doesn't exist.
Q: but Fyodor, obviously the element of the Children list is the exact same record, can't it just be that?
Well, no, there is no way to say "the exact same record", because it doesn't have a name. The compiler would be like "what record? exact same as what?"
When you declare a named record, on the other hand, you can use the very same record as element of the list, because now the record itself is a "thing". It has its own identity, which is separate from its content, so it can be referenced separately from it.
I think the error message could be clearer though.
I don't think there's any way to make an anonymous record that's recursive. The problem is that the compiler can't infer the return type of f2, and hence can't infer the type of the anonymous record's Children field. As humans, we can see that making the type recursive would solve the problem, but the compiler doesn't know that.
I agree with Fyodor's answer and I think it may be interesting to dig a bit deeper.
so lets make it a bit more explicit
here is the code that you wrote that works
type B = {
F1:string
Children: B list
}
let rec f1 (a:A) : B =
{
F1 = a.P1
Children = a.Children |> List.map f1
}
you then try to use an anonymous record to construct the equivalent issue, but lets do it explicitly and tell the compiler the type we expect using type aliases and see where it fails
type C = {| F1: string; Children: C list |} //Error is here
let rec f2 (a:A) : C =
{|
F1 = a.P1
Children = a.Children |> List.map f2
|}
so the error here is on the type alias
Severity Code Description Project File Line Suppression State
Error FS0953 This type definition involves an immediate cyclic reference through an abbreviation F# Miscellaneous Files
this type isnt allowed for the reason Fyodor explained, effectively the compiler would try to evaluate this type alias by replacing the inner C with the type alias definition and clearly this would never terminate.
(this scenario is quite common in other, but not all, languages).
This problem isn't just isolated to anonymous records, but any recursive type alias e.g.
type Foo = Foo -> Foo
The normal route out is to give the type an explicit name so usually wrapping the inner expression in a data constructor (note this is now no longer a type alias).
type C = C of {| F1: string; Children: C list |}
let rec f2 (a:A) : C =
{|
F1 = a.P1
Children = a.Children |> List.map f2
|}
|> C
and this type is basically equivalent to the explicitly named type B.
Brian's assertion that there may not be a way to make an anonymous type recursive though isnt quite correct, we can do this as long as there is some named type in the recursive definition e.g.
type C<'a> = {| F1: string; Children: 'a list |}
type D = D of C<D>
let rec f2 (a:A) : C<D> =
{|
F1 = a.P1
Children = a.Children |> List.map (f2 >> D)
|}
our f2 function is now defined in terms of a recursive anonymous record, but we've had to inject a named type into the recursion (and thus we have to use the data constructor D in our f2 function), the issue though IS that there is no anonymous (finite) type that satisfies your original function definition, not that there is, but the compiler can't find it.
it seems to be unclear as to the status of C
if we type this
let x : C<D> = {| F1=""; Children=[] |}
x.GetType();;
into FSI it replied
val it: System.Type =
<>f__AnonymousType3901454931`2[Microsoft.FSharp.Collections.FSharpList`1[FSI_0002+D],System.String]....
i.e. C is an anonymous type of type {| F1: string; Children: D list |}
we can, of course, completely dispense with this alias e.g.
type D = D of {| F1: string; Children: D list |}
let rec f2 (a:A) : {| F1: string; Children: D list |} =
{|
F1 = a.P1
Children = a.Children |> List.map (f2 >> D)
|}
let x = f2 <| A([A([A([])])])
Related
I want to write a function that takes modules that implement a certain signature and instances of the same type as those modules, but apparently I can't do that because of an issue related to the scope of the module (the module and it's instance are both parameters, therefore the instance doesn't know the type of the module).
Here is an example:
let f (type a) (module M: Set.S with type elt = a) (pr: a -> unit) (m: M.t) =
M.iter pr m;;
Where M is a Set module with elements of type a, and pr can be a printer for elements of type a.
And the message of the error caused by it (which I don't find to be super clear):
Line 1, characters 69-78:
Error: This pattern matches values of type M.t
but a pattern was expected which matches values of type 'a
The type constructor M.t would escape its scope
I tried to solve this by considering that the problem is caused by the scope of the parameters covering only the body of the function, so I put the last argument inside the body of the function like this:
let f (type a) (module M: Set.S with type elt = a) (pr : a -> unit) =
fun (m : M.t) ->
M.iter pr m;;
But the error message is still present:
Line 2, characters 7-16:
Error: This pattern matches values of type M.t
but a pattern was expected which matches values of type 'a
The type constructor M.t would escape its scope
So is there a way to do it?
OCaml core language (outside of the module system) is not dependently typed. In fantasy syntax, your function would have type function (module M: Set.S with type elt = 'a) -> ('a -> unit) -> M.t. In this type, M is a value, thus the type is dependently typed, and cannot be implemented in OCaml.
In your case, it is possible to make the type not dependent by restricting the class of modules accepted as arguments with a with constraint
let f (type a t ) (module M: Set.S with type elt = a and type t = t)
pr m = M.iter pr m
module String_set = Set.Make(String)
let () = f (module String_set) ignore String_set.empty
A possible other solution is to store the value along with the first class module and its existential quantifications:
module type packed = sig
type a
module Impl: Set.S with type elt = a
val value: Impl.t
end
let g (type a) (module P: packed with type a = a)
pr = P.Impl.iter pr P.value
But for more complex functions, there is no other choices than using functors at the module level.
Aside: if you wonder why the module type Set.S with type elt = a and type t = t in the first variant above is a (necessary) restriction consider this packed module:
let random_int_set: (module Set.S with type elt = int) =
let compare =
if Random.int 3 > 1 then Stdlib.compare
else (fun x y -> Stdlib.compare y x)
in
let module S = Set.Make(struct type t = int let compare = compare end) in
(module S)
Here, the set type is based on a random compare function. Thus the type of set is incompatible with all other Sets. Consequently, it is only possible to use such module with a packed value:
module P = struct
type a = int
module Impl = (val random_int_set)
let value = Impl.empty
end
let () = g (module P) ignore
I would like to work with the following type
type RecordPath<'a,'b> = {
Get: 'a -> 'b
Path:string
}
It's purpose is to define a getter for going from record type 'a to some field within 'a of type 'b. It also gives the path to that field for the json representation of the record.
For example, consider the following fields.
type DateWithoutTimeBecauseWeirdlyDotnetDoesNotHaveThisConcept = {
Year:uint
Month:uint
Day:uint
}
type Person = {
FullName:string
PassportNumber:string
BirthDate:DateWithoutTimeBecauseWeirdlyDotnetDoesNotHaveThisConcept
}
type Team = {
TeamName:string
TeamMembers:Person list
}
An example RecordPath might be
let birthYearPath = {
Get = fun (team:Team) -> team.TeamMembers |> List.map (fun p -> p.BirthDate.Year)
Path = "$.TeamMember[*].BirthDate.Year" //using mariadb format for json path
}
Is there some way of letting a library user create this record without ever actually needing to specify the string explicitly. Ideally there is some strongly typed way of the user specifying the fields involved. Maybe some kind of clever use of reflection?
It just occurred to me that with a language that supports macros, this would be possible. But can it be done in F#?
PS: I notice that I left out the s in "TeamMembers" in the path. This is the kind of thing I want to guard against to make it easier on the user.
As you noted in the comments, F# has a quotation mechanism that lets you do this. You can create those explicitly using <# ... #> notation or implicitly using a somewhat more elengant automatic quoting mechanism. The quotations are farily close representations of the F# code, so converting them to the desired path format is not going to be easy, but I think it can be done.
I tried to get this to work at least for your small example. First, I needed a helper function that does two transformations on the code and turns:
let x = e1 in e2 into e2[x <- e1] (using the notation e2[x <- e1] to mean a subsitution, i.e. expression e2 with all occurences of x replaced by e1)
e1 |> fun x -> e2 into e2[x <- e1]
This is all I needed for your example, but it's likely you'll need a few more cases:
open Microsoft.FSharp.Quotations
let rec simplify dict e =
let e' = simplifyOne dict e
if e' <> e then simplify dict e' else e'
and simplifyOne dict = function
| Patterns.Call(None, op, [e; Patterns.Lambda(v, body)])
when op.Name = "op_PipeRight" ->
simplify (Map.add v e dict) body
| Patterns.Let(v, e, body) -> simplify (Map.add v e dict) body
| ExprShape.ShapeVar(v) when Map.containsKey v dict -> dict.[v]
| ExprShape.ShapeVar(v) -> Expr.Var(v)
| ExprShape.ShapeLambda(v, e) -> Expr.Lambda(v, simplify dict e)
| ExprShape.ShapeCombination(o, es) ->
ExprShape.RebuildShapeCombination(o, List.map (simplify dict) es)
With this pre-processing, I managed to write an extractPath function like this:
let rec extractPath var = function
| Patterns.Call(None, op, [Patterns.Lambda(v, body); inst]) when op.Name = "Map" ->
extractPath var inst + "[*]." + extractPath v.Name body
| Patterns.PropertyGet(Some(Patterns.Var v), p, []) when v.Name = var -> p.Name
| Patterns.PropertyGet(Some e, p, []) -> extractPath var e + "." + p.Name
| e -> failwithf "Unexpected expression: %A" e
This looks for (1) a call to map function, (2) a property access on a variable that represents the data source and (3) a property access where the instance has some more property accesses.
The following now works for your small example (but probably for nothing else!)
type Path =
static member Make([<ReflectedDefinition(true)>] f:Expr<'T -> 'R>) =
match f with
| Patterns.WithValue(f, _, Patterns.Lambda(v, body)) ->
{ Get = f :?> 'T -> 'R
Path = "$." + extractPath v.Name (simplify Map.empty body) }
| _ -> failwith "Unexpected argument"
Path.Make(fun (team:Team) -> team.TeamMembers |> List.map (fun p -> p.BirthDate.Year))
The way I solved this is
let jsonPath userExpr =
let rec innerLoop expr state =
match expr with
|Patterns.Lambda(_, body) ->
innerLoop body state
|Patterns.PropertyGet(Some parent, propInfo, []) ->
sprintf ".%s%s" propInfo.Name state |> innerLoop parent
|Patterns.Call (None, _, expr1::[Patterns.Let (v, expr2, _)]) when v.Name = "mapping"->
let parentPath = innerLoop expr1 "[*]"
let childPath = innerLoop expr2 ""
parentPath + childPath
|ExprShape.ShapeVar x ->
state
|_ ->
failwithf "Unsupported expression: %A" expr
innerLoop userExpr "" |> sprintf "$%s"
type Path =
static member Make([<ReflectedDefinition(true)>] f:Expr<'T -> 'R>) =
match f with
|Patterns.WithValue(f, _, expr) ->
let path = jsonPath expr
{
Get = f :?> 'T -> 'R
Path = path
}
| _ -> failwith "Unexpected argument"
Caveat: I don't know enough about these techniques to tell if Tomas' answer performs better in some edge cases than mine.
Consider for example let f x = f x in f 1. Is its signature defined?
If so, what is it?
One could argue, that OCaml doesn't know about the fact that it's not terminating and that its type is simply inferred as 'a. Is that correct?
let a b = let rec f x = f x in f 1;;
is for example val a : 'a -> 'b eventhough it is very clear, that when a is applied, there won't be a 'b
Then requirement for a sound type system when you have type(E) = T is that if E evaluates to some value v, then v is a value that belongs to type T. A type is meaningful when the expression gives a value, and exceptions and infinite loops do not.
The type checker however is total, and gives a type for all expression, even if it is just a free type variable.
Here the return type is left unbound, and is printed as 'a.
# let f x = if x then (failwith "A") else (failwith "B");;
val f : bool -> 'a = <fun>
Here the return type of the then branch is unified with the type of the else branch:
# let f x = if x then (failwith "A") else 5;;
val f : bool -> int = <fun>
#
One way to read function types like unit -> 'a is to remember that the
type variable 'a encompasses empty types.
For example, if I have a function f
let rec f:'a. _ -> 'a = fun () -> f ()
and an empty type
type empty = |
(* using 4.07 empty variants *)
(* or *)
type (_,_) eq = Refl: ('a,'a) eq
type empty = (float,int) eq
then I can restrict the type of f to unit -> empty:
let g: unit -> empty = f
Moreover, the more general type of f can be useful in presence of branches.
For instance, I could define a return that raises an exception in order
to exit early from a for-loop:
let search pred n =
let exception Return of int in
let return: 'a. int -> 'a = fun n -> raise (Return n) in
try
for i = 0 to n do
if pred i then return i
done;
None
with Return n -> Some n
Here, the polymorphic type of return makes it possible to use it in a context
where unit was expected.
open System
open System.Collections.Generic
type Node<'a>(expr:'a, symbol:int) =
member x.Expression = expr
member x.Symbol = symbol
override x.GetHashCode() = symbol
override x.Equals(y) =
match y with
| :? Node<'a> as y -> symbol = y.Symbol
| _ -> failwith "Invalid equality for Node."
interface IComparable with
member x.CompareTo(y) =
match y with
| :? Node<'a> as y -> compare symbol y.Symbol
| _ -> failwith "Invalid comparison for Node."
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
type NodeDict<'a> = Dictionary<'a,Node<'a>>
let get_nodify_tag =
let mutable i = 0
fun () -> i <- i+1; i
let nodify (dict: NodeDict<_>) x =
match dict.TryGetValue x with
| true, x -> x
| false, _ ->
let x' = Node(x,get_nodify_tag())
dict.[x] <- x'
x'
let d = Dictionary(HashIdentity.Structural)
let nodify_ty x = nodify d x
let rec int_string_stream =
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]
In the above example, the int_string_stream gives a type error, but it neatly illustrates what I want to do. Of course, I want both sides to get tagged with the same symbol in nodify_ty. When I tried changing the Rec type to Node<Lazy<Ty>> I've found that it does not compare them correctly and each sides gets a new symbol which is useless to me.
I am working on a language, and the way I've dealt with storing recursive types up to now is by mapping Rec to an int and then substituting that with the related Ty in a dictionary whenever I need it. Currently, I am in the process of cleaning up the language, and would like to have the Rec case be Node<Ty> rather than an int.
At this point though, I am not sure what else could I try here. Could this be done somehow?
I think you will need to add some form of explicit "delay" to the discriminated union that represents your types. Without an explicit delay, you'll always end up fully evaluating the types and so there is no potential for closing the loop.
Something like this seems to work:
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
| Delayed of Lazy<Ty>
// (rest is as before)
let rec int_string_stream = Delayed(Lazy.Create(fun () ->
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]))
This will mean that when you pattern match on Ty, you'll always need to check for Delayed, evaluate the lazy value and then pattern match again, but that's probably doable!
I'm writing an F# dsl for SQL (http://github.com/kolosy/furious).
A select statement would look like this:
type person = {
personId: string
firstname: string
lastname: string
homeAddress: address
workAddress: address
altAddresses: address seq
}
and address = {
addressId: string
street1: string
zip: string
}
let (neighbor: person seq) =
db.Yield <# Seq.filter (fun p -> p.homeAddress.zip = '60614') #>
The obvious (and silly) question is... How do I parametrize the quotation?
If I just somehting like:
let z = "60614"
let (neighbor: person seq) =
db.Yield <# Seq.filter (fun p -> p.homeAddress.zip = z) #>
then z gets resolved into a static property accessor (PropertyGet(None, String z, [])). I need something that will let me retrieve the value of the variable/let binding based solely on the quotation. Ideas?
Quotations are not my forte, but check out the difference here:
let z = "60614"
let foo = <# List.filter (fun s -> s = z) #>
printfn "%A" foo
let foo2 =
let z = z
<# List.filter (fun s -> s = z) #>
printfn "%A" foo2
I think maybe having 'z' be local to the expression means the value is captured, rather than a property reference.
In addition to what Brian wrote - I believe that the encoding of access to global let bound values is also pretty stable and they will quite likely continue to be encoded as PropGet in the future.
This means that you could support this case explicitly in your translator and add a simple pre-processing step to get values of these properties. This can be done using ExprShape (which allows you to fully traverse quotation just using 4 cases). This would allow your DSL to support the general case as well.
The following function traverses quotation and replaces access to global lets with their value:
open Microsoft.FSharp.Quotations
let rec expand e =
match e with
// Extract value of global 'let' bound symbols
| Patterns.PropertyGet(None, pi, []) ->
Expr.Value(pi.GetValue(null, [| |]), e.Type)
// standard recursive processing of quotations
| ExprShape.ShapeCombination(a, b) ->
ExprShape.RebuildShapeCombination(a, b |> List.map expand)
| ExprShape.ShapeLambda(v, b) -> Expr.Lambda(v, expand b)
| ExprShape.ShapeVar(v) -> Expr.Var(v)
Then you can write the following to get a quotation that contains value instead of PropGet:
let z = 5
let eOrig = <# Seq.filter (fun p -> p = z) [ 1 .. 10 ]#>
let eNice = expand eOrig