Extension methods for F# tuples - f#
Is it possible to write extension methods for F# tuples? For example, to add instance methods .Item1 and .Item2 (like System.Tuple) which are equivalent to calling fst and snd for 2-tuples?
The System.Tuple<'T1, 'T2> type that internally represents (2-element) tuples in F# actually already has properties Item1 and Item2, but these are hidden by the F# compiler. An obvious method to add extension members to a tuple does not do the trick, so I would not expect this to work (but there may be some workaround I'm not aware of).
Generally, I think pattern matching is preferable to members such as Item1, Item2 etc. (and C# 3.0 programmers often ask for pattern matching support when working with tuples :-)).
The reason is that pattern matching forces you to name things. Compare these two code snippets:
let (width, height) = tuple
width * height
and a version using properties:
tuple.Item1 * tuple.Item2
The second is a bit shorter, but definitely less readable.
Not perfect but I'm using this. (I borrowed original code from http://www.fssnip.net/6V and added small modification.)
[<AutoOpen>]
module TupleExtensions =
type System.Tuple with
static member Item1(t) = let (x,_) = t in x
static member Item1(t) = let (x,_,_) = t in x
static member Item1(t) = let (x,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_) = t in x
static member Item1(t) = let (x,_,_,_,_,_,_) = t in x
static member Item2(t) = let (_,x) = t in x
static member Item2(t) = let (_,x,_) = t in x
static member Item2(t) = let (_,x,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_) = t in x
static member Item2(t) = let (_,x,_,_,_,_,_) = t in x
static member Item3(t) = let (_,_,x) = t in x
static member Item3(t) = let (_,_,x,_) = t in x
static member Item3(t) = let (_,_,x,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_) = t in x
static member Item3(t) = let (_,_,x,_,_,_,_) = t in x
static member Item4(t) = let (_,_,_,x) = t in x
static member Item4(t) = let (_,_,_,x,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_) = t in x
static member Item4(t) = let (_,_,_,x,_,_,_) = t in x
static member Item5(t) = let (_,_,_,_,x) = t in x
static member Item5(t) = let (_,_,_,_,x,_) = t in x
static member Item5(t) = let (_,_,_,_,x,_,_) = t in x
static member Item6(t) = let (_,_,_,_,_,x) = t in x
static member Item6(t) = let (_,_,_,_,_,x,_) = t in x
static member Item7(t) = let (_,_,_,_,_,_,x) = t in x
How to use it:
let t = (1, 2, 3)
let item1 = Tuple.Item1(t)
Tuple.Item1 defined here has advantage over fst: It is polymorphic for number of items. Once we write function which uses n tuple using these extension methods, we can extend it for n+1 tuple without modifying function body. Instead we have to modify argument type declaration. It is more effortless.
I think, what you're asking is not very functional way. You can make your own type with instance methods, but at the same time you are losing many aspects of functional programming, e.g. pattern matching.
Other than that, a DU seems to be the way to go:
type MyTuple<'T, 'U> =
| MyTuple of 'T * 'U
with
member this.MyItem1 = match this with | MyTuple(x,y) -> x
member this.MyItem2 = match this with | MyTuple(x,y) -> y
let x = MyTuple(42, "foo")
let y1 = x.MyItem1 // 42
let y2 = x.MyItem2 // "foo"
As #Tomas Petricek noted, you can't name the properties Item1 and Item2 since they already exist in System.Tuple<'T1, 'T2>. Attempting to do that will cause an error:
error FS2014: A problem occurred writing the binary [filename]: Error in pass2 for type [...], error: Error in pass2 for type MyTuple`2, error: duplicate entry 'Item1' in property table
You could also use the fst and snd functions to get the values you want (and obviously write your own for third, fourth, etc. if you really wanted to).
The workaround is to use C# style extension definitions.
This will work just fine:
open System.Runtime.CompilerServices
[<Extension>]
type TupleExtensions () =
[<Extension>] static member First((a,b)) = a
[<Extension>] static member First((a,b,c)) = a
let x = (1,2).First()
let y = (1,2,3).First()
But I agree in that it's not a good idea to access the elements of a tuple through methods, pattern matching is the best way.
Related
DRY self-replicating type
Is there a succint way to express self-replicating types in F#? — That is, without repeating oneself. // Manual self-replication type Foo (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4) = let unique = new UniqueState() // unique for every instance of Foo member this.SelfReplicate = new Foo(par1, par2, par3, par4) // repeating myself let a = new Foo(x, y, z, w) let b = a.SelfReplicate Attempt with manually injected self-replicator: // Semi-automagic self-replication type Foo' (par1 : Type1, par2 : Type2, par3 : Type3, par4 : Type4, replicate : unit -> Foo') = let unique = new UniqueState() // unique for every instance of Foo' member this.SelfReplicate = replicate() // not repeating myself let rec foo' () = new Foo'(x, y, z, w, foo') let a = foo'() let b = a.SelfReplicate I'm not sure how this can be any more succint without compiler magic. It just seems like there should be a way to capture the current arguments and type without repeating them syntactically.
You could define a type WithUnique<'T> which is a wrapper over a value of type 'T and adds a unique value to this. You may need to think about how you want the equality testing on those types to work - if you use record (as I do below), then two instances with different unique value will not be equal: let rnd = System.Random() let uniqueState() = rnd.Next() type WithUnique<'T> = { Value : 'T; Unique : int } static member Create(v) : WithUnique<'T> = { Value = v; Unique = uniqueState() } member x.Replicate() = { Value = x.Value; Unique = uniqueState() } The value of 'T is just one type, but this can be a tuple (or a record) if you need to wrap multiple things: let wu1 = WithUnique.Create( (10, "hi") ) let wu2 = wu1.Replicate() Given the above, wu1=wu2 will be false.
FSCL error on a simple example
I am trying to use openCL with FSCL on F# but I am obtaining some errors that I don't understand open FSCL.Compiler open FSCL.Language open FSCL.Runtime open Microsoft.FSharp.Linq.RuntimeHelpers open System.Runtime.InteropServices [<StructLayout(LayoutKind.Sequential)>] type gpu_point2 = struct val mutable x: float32 val mutable y: float32 new ( q ,w) = {x=q; y=w} end [<ReflectedDefinition>] let PointSum(a:gpu_point2,b:gpu_point2) = let sx =(a.x+b.x) let sy =(a.y+b.y) gpu_point2(sx,sy) [<ReflectedDefinition;Kernel>] let Modgpu(b:float32[], c:float32[],wi:WorkItemInfo) = let gid = wi.GlobalID(0) let arp = Array.zeroCreate<gpu_point2> b.Length let newpoint = gpu_point2(b.[gid],c.[gid]) arp.[gid] <- newpoint arp [<ReflectedDefinition;Kernel>] let ModSum(a:gpu_point2[],b:gpu_point2[],wi:WorkItemInfo) = let gid = wi.GlobalID(0) let cadd = Array.zeroCreate<gpu_point2> a.Length let newsum = PointSum(a.[gid],b.[gid]) cadd.[gid] <- newsum cadd [<ReflectedDefinition;Kernel>] let ModSum2(a:gpu_point2[],b:gpu_point2[],wi:WorkItemInfo) = let gid = wi.GlobalID(0) let cadd = Array.zeroCreate<gpu_point2> a.Length let newsum = gpu_point2(a.[gid].x+b.[gid].x,a.[gid].y+b.[gid].y) cadd.[gid] <- newsum cadd let ws = WorkSize(64L) let arr_s1= <# Modgpu([|0.f..63.f|],[|63.f..(-1.f)..0.f|],ws)#>.Run() let arr_s2 = <# Modgpu([|63.f..(-1.f)..0.f|],[|0.f..63.f|],ws)#>.Run() With this code when I try to use ModSum as let rsum = <# ModSum(arr_s1,arr_s2,ws)#>.Run() doesn't work, but instead when I use ModSum2 works perfectly let rsum = <# ModSum2(arr_s1,arr_s2,ws)#>.Run() The error I obtain the first time I run it is FSCL.Compiler.CompilerException: Unrecognized construct in kernel body NewObject (gpu_point2, sx, sy) and if I re-run the fsi console says System.NullReferenceException: Object reference not set to an instance of an object. The only thing I know is that the error doesn't comes from the use of another function since I can define a dot product function that works. [<ReflectedDefinition>] let PointProd(a:gpu_point2,b:gpu_point2) = let f = (a.x*b.x) let s = (a.y*b.y) f+s Thus, I guess the problem comes from the return type of PointSum, but is there a way to create such a function to sum two points and return the point type? And Why is not working? Edit/Update: Also with a record happens the same if I define the type as : [<StructLayout(LayoutKind.Sequential)>] type gpu_point_2 = {x:float32; y:float32} If I try to create a function that directly sums two gpu_point_2 on a function works, but if I call a second function it raises the same error as using a struct.
Try to add [<ReflectedDefinition>] on the constructor of gpu_point2: [<StructLayout(LayoutKind.Sequential)>] type gpu_point2 = struct val mutable x: float32 val mutable y: float32 [<ReflectedDefinition>] new (q, w) = {x=q; y=w} end Normally each code that is called from the device need this attribute, constructors included.
f# parsing string to color
type circle = { X : int; Y : int; Diameter : int; Color : Color} let mutable clickedCircle = { X = 0; Y = 0; Diameter = 0; Color = Color.White} let txtBoxVal4 = System.Enum.Parse(typeof<Color>,txtBox2.Text) clickedCircle <- {X = txtBoxVal2; Y = txtBoxVal3; Diameter = txtBoxVal1; Color = txtBoxVal4} I am trying to parse a textbox.text into a color. From this code i get the error: Error 1 This expression was expected to have type Color but here has type obj Quite new to F# and not to sure about the syntax. The error comes at "Color = txtBoxVal4"
System.Enum.Parse returns an obj type that you need to cast to the enum type. You can do that using :?> or downcast. In your case the type is known so you can use downcast. See the Casting and Conversions docs for more. clickedCircle <- {X = txtBoxVal2; Y = txtBoxVal3; Diameter = txtBoxVal1; Color = downcast txtBoxVal4}
A wrapper function for Enum.Parse could make good use of the enum constraint and eliminate the need for unboxing at the call site. module Enum = let parse<'T, 'U when 'T : enum<'U>> value = Enum.Parse(typeof<'T>, value) :?> 'T let color = Enum.parse "Black"
Creating an F# record or union type (not instance thereof) at runtime
What is the best way to create an instance of System.Type representing an F# record or union at runtime? That is, I am looking for an equivalent of FSharpType.MakeTupleType for records and unions. Just to clarify, I am not interested in creating an instance (i.e. FSharpValue.MakeRecord or FSharpValue.MakeUnion).
I am not aware of an equivalent to FSharpType.MakeTupleType for records and unions in the F# library. One way to create record or union type like structures at runtime is to use Reflection.Emit. A record type is analogous to a sealed class and a union type is an abstract base class with sealed classes for each case. For example the following function generates a minimal F# record type: open System open System.Reflection open System.Reflection.Emit let MakeRecord(typeName:string, fields:(string * Type)[]) = let name = "GeneratedAssembly" let domain = AppDomain.CurrentDomain let assembly = domain.DefineDynamicAssembly(AssemblyName(name), AssemblyBuilderAccess.RunAndSave) let name = "GeneratedModule" let dm = assembly.DefineDynamicModule(name, name+".dll") let attributes = TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Sealed let typeBuilder = dm.DefineType(typeName, attributes) let con = typeof<CompilationMappingAttribute>.GetConstructor([|typeof<SourceConstructFlags>|]) let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.RecordType|]) typeBuilder.SetCustomAttribute(customBuilder) let makeField name t = let attributes = FieldAttributes.Assembly let fieldBuilder = typeBuilder.DefineField(name+"#", t, attributes) let attributes = PropertyAttributes.None let propertyBuilder = typeBuilder.DefineProperty(name, attributes, t, [||]) let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.Field|]) propertyBuilder.SetCustomAttribute(customBuilder) let attributes = MethodAttributes.Public ||| MethodAttributes.HideBySig ||| MethodAttributes.SpecialName let methodBuilder = typeBuilder.DefineMethod("get_"+name, attributes, t, [||]) let il = methodBuilder.GetILGenerator() il.Emit(OpCodes.Ldarg_0) il.Emit(OpCodes.Ldfld, fieldBuilder) il.Emit(OpCodes.Ret) propertyBuilder.SetGetMethod(methodBuilder) fieldBuilder let types = fields |> Array.map snd let cb = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types) let il = cb.GetILGenerator() il.Emit(OpCodes.Ldarg_0) il.Emit(OpCodes.Call, typeof<obj>.GetConstructor(Type.EmptyTypes)) fields |> Array.iteri (fun i (name, t) -> let paramName = name.Substring(0,1).ToLower()+name.Substring(1) let param = cb.DefineParameter(i+1, ParameterAttributes.In, paramName) let fieldBuilder = makeField name t il.Emit(OpCodes.Ldarg_0) il.Emit(OpCodes.Ldarg, param.Position) il.Emit(OpCodes.Stfld, fieldBuilder) ) il.Emit(OpCodes.Ret) let t = typeBuilder.CreateType() assembly.Save("GeneratedModule.dll") t let r = MakeRecord("MyRecord", [|"Alpha",typeof<int>;"Beta",typeof<string>|]) Note the expected interfaces for a Record type may also need to be generated, i.e. implementations of IEquatable, IStructuralEquatable, IComparable and IStructuralComparable are missing. Update Extension methods MakeTupleType and MakeUnionType based on the code sample above are now available in the open source Fil (F# to IL Compiler) project (alpha).
f# overwrite array access operator .[]
in F#, I want to make a type of indexed array, so I can access the element by either .[i] or .[index_names] and by slice notation with index .. Is it possible to overwrite .[] like this? thanks.
define overloaded indexer in your type: type MyIndexedArray<'T>() = member this.Item(i : int) : 'T = Unchecked.defaultof<_> member this.Item(name : string) : 'T = Unchecked.defaultof<_> member this.GetSlice(a : int option, b : int option) : 'T = Unchecked.defaultof<_> let arr = new MyIndexedArray<int>() let a = arr.[1] let b = arr.["name"] let c = arr.[1..2] let d = arr.[1..] let e = arr.[..3] let f = arr.[*]