How do I define an extension method on F# lists?
A naive attempt like this results in error:
type list with
member this.abc() = 100
The correct syntax is:
type List<'a> with
member this.abc() = 100
You can use the qualified name Microsoft.FSharp.Collections.List<'a> as well, but the type abbreviation list<'a> can't be used.
That said, using module functions is more idiomatic. You should make a module function to easily combine with other functions through pipe (|>) operators:
module List =
let abc (xs: _ list) = 100
type Microsoft.FSharp.Collections.List<'T> with
member x.IsNotEmpty() = not (List.isEmpty x)
let xs = [1]
xs.IsNotEmpty
Related
given the following Discriminated Union:
type A = B of string | C of int
How can I get the constructor B name?
A.B.ToString()
// would return something like:
val it : string = "FSI_0045+it#109-19"
// when I desire
val it : string = "B"
for example with this type it works:
type D = E | F
D.E.ToString();;
val it : string = "E"
I normally get the string name of an instance of the DU with
let stringFromDU (x: 'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
But in this case, I do not have an instance, I just want to serialize the label name.
If you enable the latest language version, e.g. by passing --langversion:preview to FSI or setting
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
in your .fsproj, the following will work:
type A = B of int
let n = nameof A.B
Note: with F# 5 this will be supported out of the box :-)
You're using FSharpValue from FSharp.Reflection namespace in your example. Note that there's another class in that library for handling scenarios where you want to work with types only, FSharpType.
let cases = FSharpType.GetUnionCases(typeof<A>)
Outside of unions, it also provides helpers for other operations on F# native types.
I wish to create a function that return the largest value in a given list, Here is what I did:
let findMax aalist: 'a list=
let rec helper (l:'a list,m:'a)=
match m,l with
|m,li::lf-> if compare m li<0 then helper (lf,li)
else helper (lf,m)
|m,[] -> m
helper(aalist, aalist.Head )
But I get errors when trying to run the function :
I don't know if this is the best way to create this function. Please help.
Drop the list type annotation, so you have this:
let findMax aalist: 'a =
let rec helper (l:'a list,m:'a) =
match m,l with
| m,li::lf -> if li > m then helper (lf,li)
else helper (lf,m)
| m,[] -> m
helper(aalist, aalist.Head)
The problem is in your declaration of the parameter.
This:
let findMax aalist: 'a list=
should be:
let findMax (aalist: 'a list) =
When no parenthesis are used the compiler thinks you are specifying the return type of the function. If the return type is 'a list then the parameter aalist must be a list of lists: 'a list list.
If you do not specify any types at all, the compiler correctly deduces the type of findMax as 'a list -> 'a.
The rule is always specify parameter types within parenthesis.
I am trying to emulate a system of type classes in F#; I would like to create pair printer which automatically instantiates the right series of calls to the printing functions. My latest try, which is pasted here, fails miserably since F# cannot identify the right overload and gives up immediately:
type PrintableInt(x:int) =
member this.Print() = printfn "%d" x
let (!) x = PrintableInt(x)
type Printer() =
static member inline Print< ^a when ^a : (member Print : Unit -> Unit)>(x : ^a) =
(^a : (member Print : Unit -> Unit) x)
static member inline Print((x,y) : 'a * 'b) =
Printer.Print(x)
Printer.Print(y)
let x = (!1,!2),(!3,!4)
Printer.Print(x)
Is there any way to do so? I am doing this in the context of game development, so I cannot afford the runtime overhead of reflection, retyping and dynamic casting: either I do this statically through inlining or I don't do it at all :(
What you're trying to do is possible.
You can emulate typeclasses in F#, as Tomas said maybe is not as idiomatic as in Haskell. I think in your example you are mixing typeclasses with duck-typing, if you want to go for the typeclasses approach don't use members, use functions and static members instead.
So your code could be something like this:
type Print = Print with
static member ($) (_Printable:Print, x:string) = printfn "%s" x
static member ($) (_Printable:Print, x:int ) = printfn "%d" x
// more overloads for existing types
let inline print p = Print $ p
type Print with
static member inline ($) (_Printable:Print, (a,b) ) = print a; print b
print 5
print ((10,"hi"))
print (("hello",20), (2,"world"))
// A wrapper for Int (from your sample code)
type PrintableInt = PrintableInt of int with
static member ($) (_Printable:Print, (PrintableInt (x:int))) = printfn "%d" x
let (!) x = PrintableInt(x)
let x = (!1,!2),(!3,!4)
print x
// Create a type
type Person = {fstName : string ; lstName : string } with
// Make it member of _Printable
static member ($) (_Printable:Print, p:Person) = printfn "%s, %s" p.lstName p.fstName
print {fstName = "John"; lstName = "Doe" }
print (1 ,{fstName = "John"; lstName = "Doe" })
Note: I used an operator to avoid writing the constraints by hand, but in this case is also possible to use a named static member.
More about this technique here.
What you're trying to do is not possible (edit: apparently, it can be done - but it might not be idiomatic F#), because the constraint language cannot capture the constraints you need for the second Print operation. Basically, there is no way to write recursive constraints saying that:
Let C be a constraint specifying that the type either provides Print or it is a two-element tuple where each element satisfies C.
F# does not support type-classes and so most of the attempts to emulate them will (probably) be limited in some way or will look very unnatural. In practice, instead of trying to emulate solutions that work in other languages, it is better to look for an idiomatic F# solution to the problem.
The pretty printing that you're using as a sample would be probably implemented using Reflection or by wrapping not just integers, but also tuples.
Suppose I have type A with indexer implemented, e.g. type A is a library. Now I want to extend the indexer of it, e.g. here I want to add float number into the indexer.
I worked out the following code:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item with
get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
But it seems not working:
let a = A([| 1;2;3 |])
a.[1]
a.[1] <- 10
a.[1.0]
For the last line, I get:
Script1.fsx(243,4): error FS0001: This expression was expected to have type
int
but here has type
float
Is extending indexer possible in F#? Thanks!
This behaves differently when the type extension is defined in a separate assembly (or separate module) and when it is in the same module as the type definition.
When both are in the same module, F# compiles them into a single class and Item becomes a standard overloaded indexer - In this case, your code works as expected (and this is how you actually wrote it here).
When they are in separate modules, F# compiles the indexer as an extension member. In this case, I get the error message you described.
Adding new overloads using extension members (e.g. new method) is possible. As far I can see, the specificaton doesn't say that this shouldn't work for indexers, so I think it is a bug (can you report it to fsbugs at microsoft dot com?)
I just tried this in FSI and it seems to work.
What compiler are you using?
This is what I fed to FSI:
type A(a:int array) =
member this.Item
with get(x) = a.[x]
and set(x) value = a.[x] <- value
type A with
member m.Item
with get(x:float) = m.[x |> int]
and set(x:float) v = m.[x |> int] <- v
let a = A([| 1;2;3 |])
a.[1] <- 10
printfn "%A" a.[1.2]
This prints '10'
I am creating Linq expression trees from F# that operates on a custom datatype I have. The type is a very simple discriminated union that has the usual arithmetic operators overloaded. But for some reason I cannot create arithmetic linq expression nodes due to the fact that it can't find the correct overload. Thing is, I swear I had this working some time ago but I can't figure out what I changed to make it break.
I'll attach a small code sample showing the problem. The datatype below has the Addition operator overloaded. Using the overloaded operator works like a charm, but when I try to create an addition expression tree node using Expression.Add(lhs, rhs) the system throws an exception complaining that it can't find the overload for the Add operation.
Does anyone have an idea of what I am doing wrong?
Thank you,
Rickard
open System.Linq.Expressions
module DataType =
exception NotImplementedYet of string
type DataCarrier =
| ScalarCarrier of float
| VectorCarrier of float array
member this.Add(other) =
match (this, other) with
| ScalarCarrier(x), ScalarCarrier(y) -> ScalarCarrier(x + y)
| VectorCarrier(u), VectorCarrier(v) ->
VectorCarrier(Array.map2 (fun x y -> x + y) u v)
| _,_ -> raise (NotImplementedYet("No go!"))
static member (+) (lhs:DataCarrier, rhs) =
lhs.Add(rhs)
module Main =
let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
let clhs = Expression.Constant(lhs)
let crhs = Expression.Constant(rhs)
Expression.Add(clhs, crhs)
(* no problems with this one *)
printf "Testing operator overloading: %A" (DataType.ScalarCarrier(1.0)
+ DataType.ScalarCarrier(2.0))
(* this throws an exception *)
printf "Testing expr construction %A" (Main.createAddOp
(DataType.ScalarCarrier(1.0))
(DataType.ScalarCarrier(2.0)))
One solution is to explicitly type the Expression operands (giving them the static type DataType.DataCarrier instead of their runtime type DataType.DataCarrier.ScalarCarrier):
module Main =
let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
let clhs = Expression.Constant(lhs, typeof<DataType.DataCarrier>)
let crhs = Expression.Constant(rhs, typeof<DataType.DataCarrier>)
Expression.Add(clhs, crhs)
Another option would be to explicitly pass the addition operator to use:
module Main =
let createAddOp (lhs:DataType.DataCarrier) (rhs:DataType.DataCarrier) =
let clhs = Expression.Constant(lhs)
let crhs = Expression.Constant(rhs)
Expression.Add(clhs, crhs, typeof<DataType.DataCarrier>.GetMethod("op_Addition"))
I am surprised that your original code doesn't work, though. It appears to be a limitation in how expression trees find relevant add operators (that is, it appears that Linq only looks for add operators on the runtime types of operands).