parallel mutable assignment in F# - f#

I want to swap both references, is there a nice way make such a construct work ?
let mutable sarlast = ref (Array.copy ar)
let mutable sarcurr = ref (Array.copy ar)
... some code ...
sarcurr, sarlast <- sarlast, sarcurr

No, <- is single assignment and tuple is immutable in F#.
You can define an infix function for the purpose (one-liner suggestion by #bytebuster):
let (>-<) x y = let temp = !x in x := !y; y := temp
// Usage
let a = ref [|1|]
let b = ref [|2|]
a >-< b

Related

F# - Append an element to the beginning of a list

so I am trying to append an element to the beginning of a mutable list. This is what I am working with:
type Item<'a> =
{ mutable value: 'a
mutable next: Option<Item<'a>> }
type MList <'a> =
{ mutable first: Option<Item<'a>>
mutable last: Option<Item<'a>>
mutable size: Nat }
let appendFront<'a> (v: 'a) (l: MList <'a>): Unit =
How can I add v to the beginning of the list Mlist?
I would never think to write F# code like this, but this is what you asked for. I hope it helps.
type Nat = int // type alias, since I don't know the definition of Nat
type Item<'a> =
{ mutable Value: 'a
mutable Next: Option<Item<'a>> }
type MList<'a> =
{ mutable First: Option<Item<'a>>
mutable Last: Option<Item<'a>>
mutable Size: Nat }
let appendFront<'a> (v: 'a) (l: MList<'a>): Unit =
let newItem = { Value = v; Next = l.First }
l.First <- Some newItem
l.Size <- l.Size + 1

What is the error "A type instantiation involves a byref type." and what is a workaround in F#

I have some code wrapping TA-Lib and a lot of the wrappers are very similar:
let sma (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Sma(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
let ema (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable emaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Ema(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, emaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding emaData
What I could like to do is create a generic function where I can just pass the TA-Lib function to call. Something like:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
but the error I am getting is:
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Is there a workaround for this? I am not familiar with this issue.
Short answer: replace your mutable parameters with ref.
TA-Lib has a very unfortunate API: those pesky out-parameters (known in F# as byref), they always make trouble. In this case, they cannot be part of a generic type instantiation.
Here's a much shorter example. Consider a good old list<T>. We can make an empty list<int>:
let noInts = [] : list<int>
But what if those ints are byref?
let noRefs = [] : list< byref<int> >
No can do - says the compiler. A type instantiation involves a byref type. This is not permitted by the rules of Common IL. Sorry.
In your case, the last parameter of myGenericFunction is an F# function. In F# functions are represented by the type FSharpFunc<T, R> (where T is argument and R is result). So the type of your last parameter is this:
FSharpFunc< int * int * float array * int * byref<int> * byref<int> * float array, int >
See those two byref<int>s in there? Those are &outStartIndex and &outNbElement. And they are forbidden in a generic instantiation. Tough luck.
But there is hope!
The mutable keyword is only one of two ways to make mutable cells in F#. The other way is ref:
let x = ref 0 // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"
It's an old-school thing, predates mutable, is implemented as a library (as opposed to a language construct), and in most cases mutable is better. But this is not one of those cases!
It turns out that:
Unlike true .NET CIL out-parameters, ref cells can be part of generic instantiation just fine. Because, from .NET point of view, they're nothing special - just another class.
The F# compiler has special sauce for them: when the expected type is a ref, but you're trying to pass a function with an out-parameter in its place, the compiler will automatically generate some wrapping code for you.
So, armed with this knowledge, you can modify myGenericFunction like this:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let outStartIndex = ref 0
let outNbElement = ref 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, outStartIndex, outNbElement, smaData)
...
And then the consumers can call it like this:
myGenericFunction 42 [|1; 2; 3|] Core.Sma // Wrapping code gets generated here

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.

Loop through list of 2 tuples to replace part of a string

I'm trying to replace chained String.Replace() calls with a more functional version. Original:
let ShortenRomanNumeral (num : string) : string =
num.Replace("VIIII", "IX").Replace("IIII", "IV").Replace("LXXXX", "XC").Replace("XXXX", "XL").Replace("DCCCC", "CM").Replace("CCCC", "CD")
Functional version that works with one key value pair:
let ShortenRomanNumeral' (str : string) (k : string) (v : string) : string =
let strAfterReplace =
str.Replace(k, v)
strAfterReplace
I'm struggling to extend it to work with a list of tuples, such as
let replacements = [("VIIII", "IX"); ("IIII", "IV"); ...]
How can I write this function to apply the Replace() to the string for each key and value in the replacements list?
Fold is good. But just to demonstrate another way to do it...
// You can put the input string
// as the LAST parameter not first
let shortenRomanNumeral (k:string,v:string) (input:string) =
input.Replace(k,v)
// This allows you to do partial application like this
let replace4 = shortenRomanNumeral ("IIII", "IV")
let replace9 = shortenRomanNumeral ("VIIII", "IX")
// replace9 and replace4 have the signature string->string
// they are now simple string transformation functions
replace4 "abcIIIIdef" |> printfn "result is '%s'"
replace9 "abcVIIIIdef" |> printfn "result is '%s'"
// and they can be composed together.
// Order is important. Do 9 before 4.
let replace4and9 = replace9 >> replace4
replace4and9 "VIIII abc IIII" |> printfn "result is '%s'"
// With this approach, you can now transform a list of tuples
// into a list of string transforms using List.map
let listOfTransforms =
[("VIIII", "IX"); ("IIII", "IV");]
|> List.map shortenRomanNumeral
// and you can combine all these into one big transformation
// function using composition
let transformAll =
listOfTransforms
|> List.reduce (>>)
// finally you can apply the big function
transformAll "VIIII abc IIII" |> printfn "result is '%s'"
A fold will do the job:
let ShortenRomanNumeral' (str : string) (k : string, v : string) : string =
let strAfterReplace =
str.Replace(k, v)
strAfterReplace
let replacements = [("VIIII", "IX"); ("IIII", "IV"); ]
let replaceValues str = List.fold ShortenRomanNumeral' str replacements
replaceValues "VI VII VIIII I II III IIII" // "VI VII IX I II III IV"
Note that I only modified the last parameter of ShortenRomanNumeral' to accept tupled values.

How to convert string array to float array and substitute Double.NaN for non-numeric values?

I'm writing a parser for CSV data, and am trying to determine how to handle records
that are blank ("") or contain character data ("C"). The parser code I have below works great, but forces me to deal with the float conversions later. I'd like to be able to just make my string[][] a float[][], and handle the conversions when I parse the file, but I notice that it blows up with any non-numeric data. Ideally there would be no non-numeric or blank values, but they are unavoidable, and as such, have to be dealt with.
Can someone possibly recommend a concise approach to attempt to convert to Double, and then if it doesn't work, replace with Double.NaN instead? (Without sacrificing much performance if possible). Thank you.
let stringLine = [| "2.0"; "", "C"|]
let stringLine2Float = Array.map float stringLine
//desiredFloatArray = [| 2.0; Double.NaN; Double.NaN |]
type csvData = { mutable RowNames: string[]; mutable ColNames: string[]; mutable Data: string[][] }
let csvParse (fileString: string) =
let colNames = ((fileLines fileString |> Seq.take 1 |> Seq.nth 0).Split(',')).[1..]
let lines = fileLines fileString |> Seq.skip 1 |> Array.ofSeq
let rowNames = Array.init lines.Length string;
let allData : string [][] = Array.zeroCreate rowNames.Length
for i in 0..rowNames.Length - 1 do
let fields = lines.[i].Split(',')
allData.[i] <- fields.[1..]
rowNames.[i] <- fields.[0]
{ RowNames = rowNames; ColNames = colNames; Data = allData }
Use this instead of the built-in float conversion:
let cvt s =
let (ok,f) = System.Double.TryParse(s)
if ok then f else nan

Resources