this expression was expected to have type IDataReader but here has type SqlDataReader - f#

The following code is not casting my return value of SqlDataReader from getReader correctly to IDataReaderin the call to Seq.unfold. What am I doing wrong?
open System.Data
open System.Data.SqlClient
open System.Configuration
type Foo = { id:int; name:string }
let populateFoo (r:IDataReader) =
let o = r.GetOrdinal
{ id = o "id" |> r.GetInt32; name = o "name" |> r.GetString; }
let iter populateObject (r:IDataReader) =
match r.Read() with
| true -> Some(populateObject r, r)
| _ -> None
let iterFoo = iter populateFoo
let getReader : IDataReader =
let cnstr = ConfigurationManager.ConnectionStrings.["db"].ConnectionString
let cn = new SqlConnection(cnstr)
let cmd = new SqlCommand("select * from Foo", cn)
cmd.ExecuteReader()
let foos = Seq.unfold iterFoo getReader

F# does not automatic upcasting like C#, except in some specific scenarios (see the spec, section 14.4.2).
You have to explicitly cast the expression: cmd.ExecuteReader() :> IDataReader then you can remove the type annotation after getReader.
Alternatively you may leave that function returning an SqlDataReader and upcast at the call site:
let foos = getReader :> IDataReader |> Seq.unfold iterFoo
If unfold was a static member of a type with a signature like this one:
type T() =
static member unfold(a, b:IDataReader) = Seq.unfold a b
you would be able to do directly T.unfold(iterFoo, getReader) and it will automatically upcast. That's one of the cases mentioned in the spec.

Related

F# type constraint error trying to write a type map

I am trying to write an API on top of a C# library. The C# code has a dictionary from types to values that I would like to represent using immutable data structures.
However, I am having trouble writing the type constraints correctly:
open System
// System.Type cannot be used a map key
// TODO: Is this enough data to form a key?
type ComparableType =
{
AssemblyQualifiedName : string
}
type TypeMap<'t> =
private
| TypeMap of Map<ComparableType, 't>
module TypeMap =
let private innerMap =
function
| TypeMap m -> m
let empty () =
TypeMap Map.empty
// Here is the problem line!
let add<'t, 'v when 'v :> 't> (v : 'v) (m : TypeMap<'t>) =
let t = typeof<'v>
let k =
{
AssemblyQualifiedName = t.AssemblyQualifiedName
}
m
|> innerMap
|> Map.add k (v :> 't)
|> TypeMap
Error:
Invalid constraint: the type used for the constraint is sealed, which means the constraint could only be satisfied by at most one solution
The problem is a limitation of the F# compiler. In this code, it will assume that 'A = 'B:
type T<'A, 'B when 'A :> 'B>() = class end
The work-around is to make the type parameter of TypeMap<'t> concrete. Unfortunately this requires lots of boiler-plate, but it is a solution I can live with:
type FooTypeMap =
private
| FooTypeMap of Map<ComparableType, Foo>
module FooTypeMap =
let private innerMap =
function
| FooTypeMap m -> m
// etc...
There is a request for change here: https://github.com/fsharp/fslang-suggestions/issues/255
See also: https://stackoverflow.com/a/64113104/1256041
I do not think F# can handle a generic constraint like that. Also, it wont let you do a coertion to an undetermined type. Your best bet is to use box v instead of (v :> 't)
Like this:
type ComparableType =
{
AssemblyQualifiedName : string
}
type TypeMap =
private
| TypeMap of Map<ComparableType, obj>
module TypeMap =
let private innerMap =
function
| TypeMap m -> m
let empty () =
TypeMap Map.empty
let inline add (v : 'v) (m : TypeMap) =
let t = typeof< 'v>
let k =
{
AssemblyQualifiedName = t.AssemblyQualifiedName
}
m
|> innerMap
|> Map.add k (box v)
|> TypeMap
let inline get< ^v> (m : TypeMap) : ^v =
let t = typeof<'v>
let k =
{
AssemblyQualifiedName = t.AssemblyQualifiedName
}
(innerMap m).[k]
|> unbox

How do I condense this repetitive F# code?

EDIT: possible solutions at bottom
I'm doing some data work where I need to be very careful about string lengths that will eventually be sent in fixed width text output, stored in limited size nvarchar fields, etc. I want to have good strict typing for these rather than naked System.String types.
Suppose I've got some code like this to represent these, with a few useful module functions that play nicely with Result.map, Option.map, etc.
module String40 =
let private MaxLength = 40
type T = private T of string
let create (s:string) = checkStringLength MaxLength s |> Result.map T
let trustCreate (s:string) = checkStringLength MaxLength s |> Result.okVal |> T
let truncateCreate (s:string) = truncateStringToLength MaxLength s |> T
let toString (T s) = s
type T with
member this.AsString = this |> toString
module String100 =
let private MaxLength = 100
type T = private T of string
let create (s:string) = checkStringLength MaxLength s |> Result.map T
let trustCreate (s:string) = checkStringLength MaxLength s |> Result.okVal |> T
let truncateCreate (s:string) = truncateStringToLength MaxLength s |> T
let toString (T s) = s
type T with
member this.AsString = this |> toString
Obviously these are almost entirely repetitive with only the module name and max length different in each block.
What options are available to try and cut down on the repetitiveness here? I would love to have something like this:
type String40 = LengthLimitedString<40>
type String100 = LengthLimitedString<100>
tryToRetrieveString () // returns Result<string, ERRType>
|> Result.bind String40.create
T4 code generation doesn't seem to be an option for F# projects
Type providers seem like overkill for this kind of simple templating, and as best as I can tell they can only produce classes, not modules.
I'm aware of Scott Wlaschin's constrained strings page, but I end up with roughly the same level of repetitive code in the 'Create a type', 'Implement IWrappedString', 'create a public constructor' steps he lists.
These code blocks are fairly short and it wouldn't be the end of the world to just copy/paste a dozen times for the different field lengths. But I feel like I'm missing a simpler way to do this.
UPDATE:
One other note is that it's important that records using these types give information about what type they're carrying:
type MyRecord =
{
FirstName: String40;
LastName: String100;
}
and not be something like
type MyRecord =
{
FirstName: LimitedString;
LastName: LimitedString;
}
Tomas' answer, using the Depended Type Provider nuget library is a pretty good one, and would be a good solution for a lot of people who are fine with its behavior as-is. I felt like it would be a little tricky to extend and customize unless I wanted to maintain my own copy of a type provider which I was hoping to avoid.
Marcelo's suggestion of static parameter constraints was a fairly productive path of research. They give me basically what I was looking for -- a generic argument that is basically an 'interface' for a static methods. However the kicker is that they require inline functions to operate and I don't have the time to evaluate how much that would or would not matter in my code base.
But I took that and altered it to use regular generic constraints. It's a bit goofy to have to instantiate an object to get a max-length value, and fsharp type/generic code is just gross to look at, but from the module users's perspective it's clean, and I can easily extend this however I want.
type IMaxLengthProvider = abstract member GetMaxLength: unit -> int
type MaxLength3 () = interface IMaxLengthProvider with member this.GetMaxLength () = 3
type MaxLength4 () = interface IMaxLengthProvider with member this.GetMaxLength () = 4
module LimitedString =
type T< 'a when 'a :> IMaxLengthProvider> = private T of string
let create< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
let len = (new 't()).GetMaxLength()
match checkStringLength len s with
| Ok s ->
let x : T< 't> = s |> T
x |> Ok
| Error e -> Error e
let trustCreate< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
let len = (new 't()).GetMaxLength()
match checkStringLength len s with
| Ok s ->
let x : T< 't> = s |> T
x
| Error e ->
let msg = e |> formErrorMessage
failwith msg
let truncateCreate< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
let len = (new 't()).GetMaxLength()
let s = truncateStringToLength len s
let x : T< 't> = s |> T
x
let toString (T s) = s
type T< 'a when 'a :> IMaxLengthProvider> with
member this.AsString = this |> toString
module test =
let dotest () =
let getString () = "asd" |> Ok
let mystr =
getString ()
|> Result.bind LimitedString.create<MaxLength3>
|> Result.okVal
|> LimitedString.toString
sprintf "it is %s" mystr
I think the BoundedString type provider from the Dependent type provider project lets you do exactly what you need. Using the example from the project documentation, you can do e.g.:
type ProductDescription = BoundedString<10, 2000>
type ProductName = BoundedString<5, 50>
type Product = { Name : ProductName; Description : ProductDescription }
let newProduct (name : string) (description : string) : Product option =
match ProductName.TryCreate(name), ProductDescription.TryCreate(description) with
| Some n, Some d -> { Name = n; Description = d }
| _ -> None
I don't know how many people use this project in practice, but it seems quite simple and it does exactly what you were asking for, so it might be worth a try.
Using a touch of careful reflection magic, we can achieve a lot and get some really nice types. How about something like this?
module Strings =
type [<AbstractClass>] Length(value: int) =
member this.Value = value
let getLengthInst<'L when 'L :> Length> : 'L =
downcast typeof<'L>.GetConstructor([||]).Invoke([||])
type LimitedString<'Length when 'Length :> Length> =
private | LimitedString of maxLength: 'Length * value: string
member this.Value =
let (LimitedString(_, value)) = this in value
member this.MaxLength =
let (LimitedString(maxLength, _)) = this in maxLength.Value
module LimitedString =
let checkStringLength<'L when 'L :> Length> (str: string) =
let maxLength = getLengthInst<'L>.Value
if str.Length <= maxLength then Ok str
else Error (sprintf "String of length %d exceeded max length of %d" str.Length maxLength)
let create<'L when 'L :> Length> (str: string) =
checkStringLength<'L> str
|> Result.map (fun str -> LimitedString (getLengthInst<'L>, str))
open Strings
// === Usage ===
type Len5() = inherit Length(5)
type Len1() = inherit Length(1)
// Ok
LimitedString.create<Len5> "Hello"
// Error
LimitedString.create<Len1> "world"
One option might be to use a single module for limited-length strings that uses curried parameters for the length-limit and the string itself, then just partially apply the limit parameter. An implementation might look like this:
module LimitedString =
type T = private T of string
let create length (s:string) = checkStringLength length s |> Result.map T
let trustCreate length (s:string) = checkStringLength length s |> Result.okVal |> T
let truncateCreate length (s:string) = truncateStringToLength length s |> T
let toString (T s) = s
type T with
member this.AsString = this |> toString
Then, your modules for each length would still be required, but wouldn't have all the boilerplate:
module String100 =
let create = LimitedString.create 100
let trustCreate = LimitedString.trustCreate 100
let truncateCreate = LimitedString.truncateCreate 100
EDIT
After reading the comment and the update to the original post, I would change my suggestion a bit. Instead of defining the T type inside each module, I would have a specific struct-type single-case union for each string length at the top level. Then, I would move to toString to the individual string modules. Finally, I would add one more parameter to the LimitedString module to allow us to partially apply both the length and the specific single-case union type:
[<Struct>] type String40 = private String40 of string
[<Struct>] type String100 = private String100 of string
module LimitedString =
let create length ctor (s:string) = checkStringLength length s |> Result.map ctor
let trustCreate length ctor (s:string) = checkStringLength length s |> Result.okVal |> ctor
let truncateCreate length ctor (s:string) = truncateStringToLength length s |> ctor
module String40 =
let create = LimitedString.create 40 String40
let trustCreate = LimitedString.trustCreate 40 String40
let truncateCreate = LimitedString.truncateCreate 40 String40
let toString (String40 s) = s
module String100 =
let create = LimitedString.create 100 String100
let trustCreate = LimitedString.trustCreate 100 String100
let truncateCreate = LimitedString.truncateCreate 100 String100
let toString (String100 s) = s
type MyRecord =
{
FirstName: String40
LastName: String100
}
There's still a fair amount of boilerplate here, but I think this is in the ballpark for a solution using single-case unions and modules. A Type Provider might be possible, but you would have to consider whether the added complexity outweighs the boilerplate.
Can't you use Static Parameters, as shown on the F#.Data package's HtmlProvider example?

Reflecting let bindings in a module by attribute and type

I am trying to find let bindings with a specific attribute and type, throughout a given assembly.
For instance, the following type and attribute:
type TargetType = { somedata: string }
type MarkingAttribute() = inherit System.Attribute()
Then I would like to find the value in the following module:
module SomeModule =
[<Marking>]
let valueIWantToFind = {somedata = "yoyo"}
So what I am looking for is a function with the following signature (assuming it is suitable for a generic function signature):
let valuesOfTypeWithAttribute<'t,'attr> (assembly: Assembly) : 't list = ...
My futile attempts seem to be blocked by my lack of understanding how F# modules are translated to CLR (CLI?) classes.
I have the following FSI snippet which unfortunately finds nothing:
open System.Reflection
let types = Assembly.GetExecutingAssembly().GetTypes()
let fiWithAttribute (attributeType: System.Type) (fi: FieldInfo) =
fi.CustomAttributes
|> Seq.exists (fun attr -> attr.AttributeType = attributeType)
let fields =
types
|> Array.collect (fun t -> t.GetFields())
|> Array.filter (fiWithAttribute typeof<MarkingAttribute>)
Any help or pointers will be greatly appreciated.
Modules are compiled as classes with static members. Load your assembly into a value called assembly, and start to investigate:
> let publicTypes = assembly.GetExportedTypes ();;
val publicTypes : System.Type [] =
[|Ploeh.StackOverflow.Q36245870.TargetType;
Ploeh.StackOverflow.Q36245870.MarkingAttribute;
Ploeh.StackOverflow.Q36245870.SomeModule|]
As you can tell, SomeModule is one of those types:
> let someModule =
publicTypes |> Array.find (fun t -> t.Name.EndsWith "SomeModule");;
val someModule : System.Type = Ploeh.StackOverflow.Q36245870.SomeModule
You can now get all members of the type:
> let members = someModule.GetMembers ();;
val members : MemberInfo [] =
[|Ploeh.StackOverflow.Q36245870.TargetType get_valueIWantToFind();
System.String ToString(); Boolean Equals(System.Object);
Int32 GetHashCode(); System.Type GetType();
Ploeh.StackOverflow.Q36245870.TargetType valueIWantToFind|]
This array includes the let-bound function valueIWantToFind, and it has the desired attribute:
> let attrs = members.[5].GetCustomAttributes ();;
val attrs : System.Collections.Generic.IEnumerable<System.Attribute> =
[|Ploeh.StackOverflow.Q36245870.MarkingAttribute;
Microsoft.FSharp.Core.CompilationMappingAttribute|]
Mark's response led me onto the path of success. The reflection does not work for modules defined entirely in FSI (at least not for me in my setup).
The function I came up with looks like this:
open Microsoft.FSharp.Reflection
let letBindingsWithTypeAndAttribute<'t,'attr> (assembly: Assembly) : 't array =
let publicTypes = assembly.GetExportedTypes ()
let modules = publicTypes |> Array.filter FSharpType.IsModule
let members = modules |> Array.collect (fun m -> m.GetMembers ())
let miHasAttribute (mi : MemberInfo) =
mi.GetCustomAttributes ()
|> Seq.exists (fun attr' -> attr'.GetType() = typeof<'attr>)
let withAttr =
members
|> Array.filter miHasAttribute
let valueOfBinding (mi : MemberInfo) =
let property = mi.Name
mi.DeclaringType.GetProperty(property).GetValue null
withAttr
|> Array.map valueOfBinding
|> Array.choose (fun o -> match o with
| :? 't as x -> Some x
| _ -> None)

IEnumerable and array comprehension

I wonder why the second line reports a compiler error
the type Relations is not compatible with seq<'a>
while the first infers a type Relation for r.
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
What precise property makes it possible to loop over Relations using for?
// Edit reproduction step :
I create a blank solution in VS2012, add a reference to Microsoft.Office.Interop.Access.Dao, and paste the code below.
module toto =
type Class1() =
member this.X = "F#"
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
r is typed as Relation, and not obj
This doesn't entirely mesh with what you've said, but one scenario in which a sequence expression would work but not Seq.map is when a type implements System.Collections.IEnumerable but not System.Collections.Generic.IEnumerable<'T> (aka seq<'T>). For example, in this code t is inferred as obj list, but the next line doesn't compile.
type T() =
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (Seq.init 10 id).GetEnumerator() :> _
let t = [for x in T() -> x]
let t2 = T() |> Seq.map id //ERROR: The type 'T' is not compatible with the type 'seq<'a>'
This scenario is especially common for libraries created prior to .NET 2.0.

how do i fix these errors generated by my computational expression that is using my custom workflow builder?

From the MSDN documentation I understand that if Run is implemented it will be called automatically at the end of the computational expression. It says that:
builder.Run(builder.Delay(fun () -> {| cexpr |}))
will be generated for the computational expression. Run and/or Delay will be omitted if they are not defined in the workflow builder. I was expecting my ReaderBuilder to return a list of MyItem objects when Run is called automatically. So I do not understand why I'm getting a type mismatch error. The errors are generated by the return statement inside the ProcedureBuilder foo at the end of my code listing here. Could someone please explain what I'm misunderstanding about workflow builders and what I have implemented incorrectly?
I'm getting the following errors:
The type ''a list' is not compatible with the type 'ReaderBuilder'
Type constraint mismatch. The type 'a list is not compatible with type ReaderBuilder The type ''a list' is not compatible with the type 'ReaderBuilder'
open System
open System.Data
open System.Data.Common
open System.Configuration
let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)
type Direction =
| In
| Out
| Ref
| Return
type dbType =
| Int32
| String of int
type ReaderBuilder(cmd) =
let mutable items = []
member x.Foo = 2
member x.YieldFrom item =
items <- item::items
item
member x.Run item =
items
type ProcBuilder(procedureName:string) =
let name = procedureName
let mutable parameters = []
let mutable cmd:DbCommand = null
let mutable data = []
member x.Command with get() = cmd
member x.CreateCommand() =
factory.CreateCommand()
member x.AddParameter(p:string*dbType*Direction) =
parameters <- p::parameters
member x.Bind(v,f) =
f v
member x.Reader = ReaderBuilder(cmd)
member x.Return(rBuilder:ReaderBuilder) =
data
let (?<-) (builder:ProcBuilder) (prop:string) (value:'t) =
builder.Command.Parameters.[prop].Value <- value
type MyItem() =
let mutable _a = 0
let mutable _b = String.Empty
let mutable _c = DateTime.Now
member x.a
with get() = _a
and set n = _a <- n
member x.b
with get() = _b
and set n = _b <- n
member x.c
with get() = _c
and set n = _c <- n
let proc name = ProcBuilder(name)
let (%) (builder:ProcBuilder) (p:string*dbType*Direction) =
builder.AddParameter(p)
builder
let (?) (r:DbDataReader) (s:string) = r.GetOrdinal(s)
let foo x y =
let foo = proc "foo" % ("x", Int32, In) % ("y", String(15), In)
foo?x <- x
foo?y <- y
foo {
do! foo?x <- x
do! foo?y <- y
return foo.Reader {
let item = MyItem()
item.a <- r.GetInt32("a")
item.b <- r.GetString("b")
item.c <- r.GetDateTime("c")
yield! item
}
}
The problem in your example is that the foo.Reader { ... } block has a return type MyItem list (because this is what the Run member of the ReaderBuilder type returns). However, the Return member of ProcBuilder expects an argument of type ReaderBuilder.
The data field of ReaderBuilder will be always an empty list, so this is also suspicious. I think you probably want to change the Return of ProcBuilder to take an argument MyItem list instead.
However, I think that using custom computation builder for database access doesn't really give you much advantage. You're not creating a "non-standard computation" in some sense. Instead, you probably just want a nice syntax for calling commands & reading data. Using the dynamic operator can make this quite elegant even without computation builders - I wrote an article about this some time ago.

Resources