I have the following interface:
type IFactory<'TIn, 'TOut> =
abstract Create: 'TIn -> 'TOut
I am trying to write a ComposedFactory. The following appears to be correct syntax as VS is not complaining about it:
type ComposedFactory<'TIn, 'TMid, 'TOut>
(midFactory: IFactory<'TIn, 'TMid>,
outFactory: IFactory<'TMid, 'TOut>) =
let Create' =
midFactory.Create >> outFactory.Create
interface IFactory<'TIn, 'TOut> with
member __.Create x = Create' x
But the fact that I am defining "Create" twice feels stupid. I want the interface one only. How can I do that?
You can do this for sport:
type ComposedFactory<'TIn, 'TMid, 'TOut>
(midFactory: IFactory<'TIn, 'TMid>,
outFactory: IFactory<'TMid, 'TOut>) =
interface IFactory<'TIn, 'TOut> with
member __.Create x = (midFactory.Create >> outFactory.Create) x
But I can't call it preferable by any means to what you had before.
I can't figure out how to do what you want to do I'm afraid. I would guess that an implementation of an interface function explicitly requires the parameters to be specified in its definition.
The best alternative I can suggest to you is piping:
member __.Create x = x |> midFactory.Create |> outFactory.Create
Related
Background: I am trying to expand my existing logging framework, which is currently a wrapper of static non-thread-safe methods over printfn and friends. My design goals are: having a generic interface ILog and concrete classes like Dbg, Log, Trace. I cannot use modules and functions, unfortunately, because I like to leverage the ConditionalAttribute on the methods.
I have a working approach that looks something like this:
type ILog<'T, 'U, 'V> =
abstract member log: 'T -> unit
abstract member log: 'U * 'V -> unit
type Dbg<'T, 'U, 'V when 'T :> Printf.StringFormat<string> and 'U :> Printf.StringFormat<'V -> string>>() =
static member inline _do_other_stuff() = "other stuff"
static member inline private _helper() =
printfn "%s %s" (Dbg<_,_,_>._do_other_stuff())
interface ILog<'T, 'U, 'V> with
[<Conditional("DEBUG")>] // removed from call site
member this.log(msg) = sprintf msg |> Dbg<_,_,_>._helper()
[<Conditional("DEBUG")>] // removed from call site
member this.log(fmt, a) = sprintf fmt a |> Dbg<_,_,_>._helper()
module TestMe =
let test() =
let dbg = new Dbg<_,_,_>() :> ILog<_,_,_>
dbg.log("test%i", 2)
Here, the compiler and syntax checker and coloring detects properly the dbg.log("test%i", 2) line, which is exactly what I want. It will also properly raise an error if I were to write "test%s" instead.
Now, if I take the above approach and expand it to create more overloads of the ILog.log method, this gets pretty hairy pretty quickly because of all the type annotations and the required use of syntax like Dbg<_,_,_>. Some of it can be hidden away, but still I figured there must be a better way.
One approach I tried, which seemed very FSharpish is:
type ILog =
abstract member log: _ -> unit
abstract member log: _ * _ -> unit
This compiles the interface and infers the type to be 'a0 and 'a0 -> 'a1 respectively (which seems wrong, why is the second log member getting the same 'a0?). But, I can't find any way of implementing such overly generic interface:
type Dbg() =
interface ILog with
member this.log v = v + 1 |> ignore // it won't infer int here
It raises:
The declared type parameter '?' cannot be used here, since the type parameter cannot be resolved at compile time.
Does F# 4.0 have a way of declaring interfaces in a more generic way, or am I stuck to having to declare them specifically (while this works, it is tedious).
Since I can do this:
case class A(a: Int)
trait C
val x = new A(10) with C
Why can't I do this:
type X = A with C
val x = new X(10)
? If I can't even construct an instance, what's the use case of type X = A with C?
The error message that you get should give you a hint:
error: class type required but A with C found
new X(10)
^
X, as a type alias, gets rewritten to an A with C type expression, which is not a class type. The latter, according to the Scala Language Specification, is:
a type designator
(ยง
3.2.3
) that refers to a a class or a trait
(emphasis mine)
In other words, it's not every type expression.
This is not an authoritative answer, but I don't believe it's possible to define a type alias in such a way that it becomes a class type. On the one hand, a new expression theoretically accepts an AnnotType, as defined in Section 5.1.1. However, I don't see how, using the type alias grammar from Section 4.3, you could specify what constructor are you using etc..
tl;dr - unless your type alias is directly rewritable to a class type (e.g. A in your example), you can't use it as a class type, which includes invoking new with it. If you want that, you need a class declaration, i.e. class X(a: Int) extends A(a) with C.
Regarding your second question, you say you can't instantiate X. Ah, but that's where you're wrong! Let me show you an example, based on your code:
def blah(x: X) = x.toString
val x = new A(10) with C
val y = new A(10)
blah(x) //String = A(10)
blah(y) //type error
So, it's useful whenever you need a type constraint, since the "aliased" type will be matched to the type alias, even if it wasn't explicitly declared as such.
It is beyond me at this point. I'm trying to create an interface that looks something like
this.
type IFetchData =
abstract FetchData: string -> seq<'a>
The above declaration is valid (and compiles) but when I go to use it I get a compile time error. This expression was expected to have type 'a but here has type "what I'm currently trying to return" i.e. seq.
My example usage however looks like the following:
type SampleFetchData() =
interface IFetchData with
member self.FetchData str =
seq {
for letter in str do
yield letter // compile error here
}
I'm not sure what I'm doing wrong. All I'd like to do is allow the interface implementer to be able to write any function that returns a generic sequence either seq<string>,seq<int>,seq<record type here>, seq<union type here>, etc.
Can someone tell me what I'm missing here?
Thanks.
If you're loading the interface implementation using Reflection, then it is going to be quite difficult to work with it. The problem is that you get an object of type obj. You know that it implements IFetchData<'T> for some 'T, but statically, you don't know for which 'T. This is a problem because you can't cast the object to any more specific type - if you tried using IFetchData<obj>, it wouldn't work because you can't cast, for example, IFetchData<int> to that type.
I would recommend using a non-generic interface, which is quite common .NET pattern:
type IFetchDataUntyped =
abstract FetchData : string -> System.Collections.IEnumerable
type IFetchData<'T> =
inherit IFetchDataUntyped
abstract FetchData : string -> seq<'T>
When you load an implementation using Reflection, you can cast the object to IFetchDataUntyped and work with it in a fairly reasonable way (using Seq.cast to convert the sequence to a more specific type if you know the element type).
Depending on your application, you may also just make the FetchData method a generic method and keep the interface non-generic. Then you could cast dynamically loaded objects to the interface and invoke the method. However, this changes the design (because the method has to work for any type it gets as a type parameter):
type IFetchData =
abstract FetchData<'T> : string -> seq<'T> // Note: Generic parameter here!
You need to do something like
type IFetchData<'a> =
abstract FetchData: string -> seq<'a>
type SampleFetchData() =
interface IFetchData<char> with
member self.FetchData str =
seq {
for letter in str do
yield letter
}
i.e. the interface needs to be made generic. If you want to avoid the genericness you could use some inline constraints, rather than an interface
EDIT: Inline magic version
let inline Fetchdata string obj=
(^a: (member FetchData: string -> seq<'b> )(obj, string))
type SampleFetchData() =
member self.FetchData str =
seq {
for letter in str do
yield letter
}
Fetchdata "hello" (new SampleFetchData())
I have several types that implement an interface. Equality for these types only depends on interface members. Is it possible to define equality for these types once, without overriding Equals or op_Equality for each type?
EDIT
I tried the following, but, for whatever reason, it overrode every use of =, even for types not implementing IEntity.
[<AutoOpen>]
module Equality =
let inline op_Equality (left:IEntity) (right:IEntity) = true
I also tried using flexible types (#IEntity). Same result.
What you're trying to do is something that mixins or typeclasses might enable in other languages; unfortunately there isn't equivalent functionality in F#. Your best bet is probably one of the following options:
Use an abstract base class instead of an interface.
Write your equality method outside of your type and then have all of your implementations defer to it. For example,
let entityEquals (i1:IEntity) (i2:IEntity) =
i1.Member1 = i2.Member1 &&
i1.Member2 = i2.Member2 &&
...
type MyEntity() =
interface IEntity with
member x.Member1 = ...
...
override x.Equals(y) =
match y with
| :? IEntity as y -> entityEquals x y
| _ -> false
override x.GetHashCode() =
...
In addition to a bit of boilerplate, the downside here is that if anyone else implements your IEntity interface, they aren't forced to use your equality method - it's opt-in.
Create an another operator which you use for equality testing of IEntitys:
let (==) (i1:IEntity) (i2:IEntity) =
i1.Member1 = i2.Member1 &&
...
The (huge) downside of this is that structural equality of types containing IEntitys (such as tuples, records, etc.) won't use this operator to compare those components, which is likely to lead to surprising broken code.
I don't think there is a way to do this in a static way. The problem is that extension members (e.g. if you added op_Equality as an extension) are ignored by static member constraints (e.g. if you also redefined = using inlin with op_Equality requirement).
The F# compiler has some special powers available only when compiling FSharp.Core.dll that could help (search sources for the declaration let inline GenericOne). It uses something like static type switch - but this cannot be accessed by mere mortals.
So, I don't have any idea better than using dynamic type test, which isn't really a good approach and it's probably better to define a custom operator for comparison of your interfaces.
For a reference, the ugly dynamic approach would be:
let inline (=) a b =
match a, b with
| :? IFoo as a, :? IFoo as b -> yourEquals a b
| _ -> a = b
I am attempting to simulate an interface in OCaml and am using the "type" construct. I have two types:
type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;
...and would like to define a particular fooSansBar:
let fsb = {a="a"; b=3};;
...but am told that the bar field is not defined. From this, it appears that, contrary to the values I passed in matching fooSansBar's signature, the system believes I am trying to create a fooConBar. Is it possible to create a fooSansBar if the two types as defined above exist?
Additionally (because I'm new to OCaml) is there a better way to simulate an interface?
In OCaml, field names in record types must be unique, so the two types you define cannot coexist simultaneously. Caml is the only language I know with this property.
Because the second definition hides the first, when the compiler sees the a and b fields it expects them to belong to the fooConBar type and so complains of the missing bar field.
If you are trying to simulate an interface, the correct functional way to do it in Caml is to define a module type.
module type FOO_CON_BAR = sig
val a : string
val b : int
val bar : char
end
And an instance:
module Example = struct
let a = "hello"
let b = 99
let c = '\n'
end
With modules and module types you also get subtyping; there's no need to resort to objects.
P.S. My Caml is rusty; syntax may be off.
There are several possible solutions in OCaml depending how you're using the code you gave. The simplest is to combine the two types:
type fooBar = { a: string; b: int; bar: char option }
Another solution is to replace the records with objects because objects support subtyping (and can have their types inferred so there is no need to declare a type!):
# let fsb = object
method a = "a"
method b = 3
end;;
val fsb : < a : string; b : int > = <obj>
# fsb#a, fsb#b;;
- : string * int = ("a", 3)
The second type redefines a and b, effectively hiding the first, which is why it cannot be constructed any more. You could define these types in different modules, but that would be the same as using a different name for a and b.
These constructs can only be used when you do not try to "derive" from another interface, but just implement it.
If you wish to use these object oriented concepts in Ocaml, you could look at the object system, or, depending on your problem, the module system. Alternatively, you could try to solve your problem in a functional way. What problem are you trying to solve?
OCaml provides two ways to implement interfaces. One, as already mentioned, is a module type.
The other is a class type. You can write a class type (interface) fooSansBar:
class type fooSansBar = object
method a: string
method b: int
end
and a class type fooConBar:
class type fooConBar = object
inherit fooSansBar
method bar: char
end
This will allow you to use a fooConBar anywhere a fooSansBar is required. You can now create a fooSansBar, using type inference:
let fsb = object
method a = "a"
method b = 3
end
Now, fsb's type happens to be <a: string; b: int>, as indicated by Jon, but it's perfectly usable as a fooSansBar due to OCaml's structural subtyping.
In OCaml, it's not possible to have two record types with intersecting field sets present in the same scope.
If you really need to use record types with intersecting field sets, then you can work around this restriction by enclosing the types within their own dedicated modules:
module FooSansBar = struct type t = {a:string; b:int} end
module FooConBar = struct type t = {a:string; b:int; bar:char} end
Then you can construct instances of these types like so:
let fsb = {FooSansBar.a="a"; b=3}
let fcb = {FooConBar.a="a"; b=4; bar='c'}
These instances have the following types:
fsb : FooSansBar.t
fcb : FooConBar.t