I'm trying to make a struct in F# for representing depth curves in a sea map. It has to contain a list of coordinates and a float telling what depth is represented (eg. "4.5 meters"). I have made it this way:
type Coord =
struct
val X : float
val Y : float
new(x,y) = { X = x ; Y = y }
end
type DepthCurve =
struct
val Coords : list<Coord>
val Depth : float
new(list_of_Coords, depth) = { Coords = list_of_Coords ; Depth = depth}
end
let myCoord1 = new Coord(1.,2.)
let myCoord2 = new Coord(3.,4.)
let myDepthCurve = new DepthCurve([myCoord1;myCoord2] , 5. )
My problem is that this doesn't let me create the Polygon and its Coords in one go, like this:
let myDepthCurve = {coords=[[1.;2.];[3.;4.]] , 5}
There do exist a solution for this:
type Coord = { X : float; Y : float }
type 'a DepthCurve = {coords: 'a list;}
let myDepthCurve = {coords=[[1.;2.];[3.;4.]]};;
but it doesn't let me have the depth-indicating float in the struct as well, and it doesn't let me restrict types of the list to be only Coords.
How do I combine the best from both worlds?
The object types you created are standard .NET-structures with a constructor - They don't have the special F#-record-initialization sytnax ({ ... }).
For your problem, you could just write a little wrapper function:
let curve depth coords = New DepthCurve([for (x, y) in coords -> New Coord(x, y)], depth)
used like this
let testCurve = curve 10. [(1., 2.); (3., 4.); ...]
When declaring your structures in the shortened record syntax, you should do it like this:
type Coord = float * float // Type-alias for a 2D-float-tuple
type DepthCurve = { coords : Coord list; depth : float }
let myCurve = { coords = [(1., 2.); ...], depth = 42. }
There is no reason why you should use a generic list, just specify Coord list (meaning List of Coords). And please note the difference between a list ([1; 2; 3]) and a tuple ((1, 2, 3)). The latter are much more suitable for representing coords.
Please take a look at this article on F# structures and types.
The answer depends from the way you construct your program.
For case you activly use functional paradigm (no mutation, high-order functions, pattern matching) i vote for three choices:
(* tuple with type constractor and any getters you need: *)
let makeCoord x y = (x,y)
let makeCurve depth coords = (depth,coords)
let addCurveCoord (depth,coords) coord = (depth, coord::coords)
let getCurveDepth (depth,_) = depth
let getCurveCoords (_,coords) = coords
let getFirstCurveCoord (_,coords) = List.hd coords
//...
(* or types described by Dario *)
(* or tagged unions for case you need specific access to parts of your data *)
for case you prefer OOP you can create simple object hierarchy.
The main advantage of FP is easy modification of your design at any step of program constraction. But of course, it cost to your by explicit state arguments. But may beat them by monadic expressions :)
Related
I am currently using map property with a closure in Swift to extract linear factors from an array and calculate a list of musical frequencies spanning one octave.
let tonic: Double = 261.626 // middle C
let factors = [ 1.0, 1.125, 1.25, 1.333, 1.5, 1.625, 1.875]
let frequencies = factors.map { $0 * tonic }
print(frequencies)
// [261.62599999999998, 294.32925, 327.03249999999997, 348.74745799999994, 392.43899999999996, 425.14224999999999, 490.54874999999993]
I want to do this by making the closure extract two integers from a string and divide them to form each factor. The string comes from an SCL tuning file and might look something like this:
// C D E F G A B
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
Can this be done ?
SOLUTION
Thankfully, yes it can. In three Swift statements tuning ratios represented as fractions since before Ptolemy can be coverted into precise frequencies. A slight modification to the accepted answer makes it possible to derive the list of frequencies. Here is the code
import UIKit
class ViewController: UIViewController {
// Diatonic scale
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
// Mohajira scale
// let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
override func viewDidLoad() {
super.viewDidLoad()
_ = Tuning(ratios: ratios)
}
}
Tuning Class
import UIKit
class Tuning {
let tonic = 261.626 // frequency of middle C (in Hertz)
var ratios = [String]()
init(ratios: [String]) {
self.ratios = ratios
let frequencies = ratios.map { s -> Double in
let integers = s.characters.split(separator: "/").map(String.init).map({ Double($0) })
return (integers[0]!/integers[1]!) * tonic
}
print("// \(frequencies)")
}
}
And here is the list of frequencies in Hertz corresponding to notes of the diatonic scale
C D E F G A B
[261.626007, 294.329254, 327.032501, 348.834686, 392.439026, 441.493896, 490.548767]
It works for other scales with pitches not usually found on a black-and-white-note music keyboard
Mohajira scale created by Jacques Dudon
// D F G C'
let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
And here is a list of frequencies produced
// D F G C'
// [274.70729999999998, 294.32925, 313.95119999999997, 320.49185, 348.83466666666664, 366.27639999999997, 392.43899999999996, 418.60159999999996, 427.32246666666663, 470.92679999999996, 479.64766666666662, 523.25199999999995]
Disclaimer
Currently the closure only handles rational scales. To fully comply with Scala SCL format it must also be able to distinguish between strings with fractions and strings with a decimal point and interpret the latter using cents, i.e. logarithmic rather than linear factors.
Thank you KangKang Adrian and Atem
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
let factors = ratios.map { s -> Float in
let integers = s.characters.split(separator: "/").map(String.init).map({ Float($0) })
return integers[0]!/integers[1]!
}
If I understand your question, you can do something like that:
func linearFactors(from string: String) -> Double? {
let components = string.components(separatedBy: "/").flatMap { Double($0) }
if let numerator = components.first, let denominator = components.last {
return numerator / denominator
}
return nil
}
Convert ratios to array of double
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
let array = ratios.flatMap { element in
let parts = element.components(separatedBy: "/")
guard parts.count == 2,
let dividend = Double(parts[0]),
let divisor = Double(parts[1]),
divisor != 0
else {
return nil
}
return parts[0] / parts[1]
}
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.
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"
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.
Let's consider the following enum in C#
public enum ScrollMode : byte
{
None = 0,
Left = 1,
Right = 2,
Up = 3,
Down = 4
}
The F# code receives a byte and has to return an instance of the enum
I have tried
let mode = 1uy
let x = (ScrollMode)mode
(Of course in the real application I do not get to set 'mode',
it is received as part of network data).
The example above does not compile, any suggestions?
For enums whose underlying type is 'int', the 'enum' function will do the conversion, but for non-int enums, you need 'LanguagePrimitives.EnumOfValue', a la:
// define an enumerated type with an sbyte implementation
type EnumType =
| Zero = 0y
| Ten = 10y
// examples to convert to and from
let x = sbyte EnumType.Zero
let y : EnumType = LanguagePrimitives.EnumOfValue 10y
(EnumOfValue is listed here
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Core.LanguagePrimitives.html
(now http://msdn.microsoft.com/en-us/library/ee340276(VS.100).aspx )
whereas enum is listed here
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Core.Operators.html
(now http://msdn.microsoft.com/en-us/library/ee353754(VS.100).aspx )
)
let x : ScrollMode = enum mode