Auto-generated static field in F# class/module prevents creation of SQL CLR function - sql-server

I'm trying to write a CLR user-defined function in F#, but CREATE ASSEMBLY gives the error:
CREATE ASSEMBLY failed because type 'StringMetrics' in safe assembly 'MyNamespace.SqlServer.Text' has a static field 'field1776#'. Attributes of static fields in safe assemblies must be marked readonly in Visual C#, ReadOnly in Visual Basic, or initonly in Visual C++ and intermediate language.
Here's how it looks in Reflector. This is not a field I've explicitly created.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal static <PrivateImplementationDetails$MyNamespace-SqlServer-Text>.T1775_18Bytes# field1776#; // data size: 18 bytes
I've tried using a module and a class. Both generate the field, just in different places. What is this field for? Is there a way to avoid its creation? Is there another approach I should be using to create a CLR function in F#? Is it even possible?
Complete Code
namespace MyNamespace.SqlServer.Text
module StringMetrics =
open System
open System.Collections.Generic
open System.Data
open System.Data.SqlTypes
[<CompiledName("FuzzyMatch")>]
let fuzzyMatch (strA:SqlString) (strB:SqlString) =
if strA.IsNull || strB.IsNull then SqlInt32.Zero
else
let comparer = StringComparer.OrdinalIgnoreCase
let wordBoundaries = [|' '; '\t'; '\n'; '\r'; ','; ':'; ';'; '('; ')'|]
let stringEquals a b = comparer.Equals(a, b)
let isSubstring (search:string) (find:string) = find.Length >= search.Length / 2 && search.IndexOf(find, StringComparison.OrdinalIgnoreCase) >= 0
let split (str:string) = str.Split(wordBoundaries)
let score (strA:string) (strB:string) =
if stringEquals strA strB then strA.Length * 3
else
let lenA, lenB = strA.Length, strB.Length
if strA |> isSubstring strB then lenA * 2
elif strB |> isSubstring strA then lenB * 2
else 0
let arrA, arrB = split strA.Value, split strB.Value
let dictA, dictB = Dictionary(), Dictionary()
arrA |> Seq.iteri (fun i a ->
arrB |> Seq.iteri (fun j b ->
match score a b with
| 0 -> ()
| s ->
match dictB.TryGetValue(j) with
| true, (s', i') -> //'
if s > s' then //'
dictA.Add(i, j)
dictB.[j] <- (s, i)
| _ ->
dictA.Add(i, j)
dictB.Add(j, (s, i))))
let matchScore = dictB |> Seq.sumBy (function (KeyValue(_, (s, _))) -> s)
let nonMatchA =
arrA
|> Seq.mapi (fun i a -> i, a)
|> Seq.fold (fun s (i, a) ->
if dictA.ContainsKey(i) then s
else s + a.Length) 0
let wordsB = HashSet(seq { for (KeyValue(i, _)) in dictB -> arrB.[i] }, comparer)
let nonMatchB =
arrB |> Seq.fold (fun s b ->
if wordsB.Add(b) then s + b.Length
else s) 0
SqlInt32(matchScore - nonMatchA - nonMatchB)

It seems it's generated by the wordBoundaries array. If you express it as a list instead, and convert it to an array at runtime, this internal static field is not generated:
let wordBoundaries = Array.ofList [' '; '\t'; '\n'; '\r'; ','; ':'; ';'; '('; ')']
However, it seems that also the function itself is represented as a static, non-readonly
field:
public static SqlInt32 fuzzyMatch(SqlString strA, SqlString strB);
Maybe using a class instead of a module cures this.

Related

rscala package: How to access the elements of Scala cached reference Array in R

I am using rscala to communicate Scala and R. Lets say I have a Scala function that returns an Array of Array[Double] and a Double as:
Array(projectedTrainToMatrix,predictedTrain,kernelParam,projection,thresholdsToArray)
where kernelParam is of type Double and the others are Array[Double]. When I run the method from R as:
myfit<-s$.cristinahg.ocapis.kdlor$kdlorfit(traindata,trainlabels,kerneltype,params)
I get myfit as
ScalaCachedReference... _: Array[Array[_]]
[Ljava.lang.Object;#b9dfc5a
But I want to access each of the values in myfitArray. I have tried to access them via myfit$'(1)' but I get this instead the desired Array of Double:
function (..., .AS.REFERENCE = NA, .EVALUATE = TRUE, .PARENTHESES = FALSE)
{
args <- list(...)
if (!is.null(names(args)))
stop("Arguments should not have names.")
names <- paste0(rep("$", length(args)), seq_len(length(args)))
header <- mkHeader(args, names)
identifier <- ""
body <- if (inherits(reference, "ScalaInterpreterReference"))
paste0(reference[["identifier"]], ".", method)
else if (inherits(reference, "ScalaCachedReference")) {
if (.EVALUATE) {
identifier <- reference[["identifier"]]
paste0("R.cached($0).asInstanceOf[", reference[["type"]],
"].", method)
}
else {
paste0("R.cached(\\"", reference[["identifier"]],
"\\").asInstanceOf[", reference[["type"]], "].",
method)
}
}
else if (inherits(reference, "ScalaInterpreterItem")) {
if (method == "new")
paste0("new ", reference[["snippet"]])
else paste0(reference[["snippet"]], ".", method)
}
else stop("Unrecognized reference type.")
argsList <- paste0(names, collapse = ",")
if ((nchar(argsList) > 0) || .PARENTHESES)
argsList <- paste0("(", argsList, ")")
snippet <- paste0(header, paste0(body, argsList))
if (get("show.snippet", envir = interpreter[["env"]]))
cat("<<<\\n", snippet, "\\n>>>\\n", sep = "")
cc(interpreter)
wb(interpreter, DEF)
wc(interpreter, snippet)
flush(interpreter[["socketIn"]])
status <- rb(interpreter, "integer")
if (status != OK) {
if (get("serializeOutput", envir = interpreter[["env"]]))
echoResponseScala(interpreter)
stop("Problem defining function.")
}
functionName <- rc(interpreter)
if (get("serializeOutput", envir = interpreter[["env"]]))
echoResponseScala(interpreter)
f <- function(..., .NBACK = 1) {
args <- list(...)
if (length(args) != length(names))
stop("Incorrect number of arguments.")
if (!is.null(names(args)))
stop("Arguments should not have names.")
workspace <- new.env(parent = parent.frame(.NBACK))
assign(".rsI", interpreter, envir = workspace)
for (i in seq_len(length(args))) assign(names[i], args[[i]],
envir = workspace)
cc(interpreter)
wb(interpreter, INVOKE)
wc(interpreter, functionName)
wc(interpreter, identifier)
flush(interpreter[["socketIn"]])
rServe(interpreter, TRUE, workspace)
status <- rb(interpreter, "integer")
if (get("serializeOutput", envir = interpreter[["env"]]))
echoResponseScala(interpreter)
if (status != OK)
stop("Problem invoking function.")
result <- scalaGet(interpreter, "?", .AS.REFERENCE)
if (is.null(result))
invisible(result)
else result
}
if (.EVALUATE)
f(..., .NBACK = 2)
else f
}
<bytecode: 0x55b1ba98b3f8>
<environment: 0x55b1bd2616c0>
So how can I access each element of the Scala Array in R?
Your example shows that you are using rscala < 3.0.0. While it could be done in older versions, I recommend you use a recent version on CRAN. Below I provide a solution using rscala 3.1.0.
library(rscala)
scala()
s + '
def kdlorfit(
projectedTrainToMatrix: Array[Double], predictedTrain: Array[Double],
kernelParam: Double, projection: Array[Double], thresholdsToArray: Array[Double]) =
{
Array(projectedTrainToMatrix,predictedTrain,kernelParam,projection,thresholdsToArray)
}
'
x1 <- c(1,2,3)
x2 <- c(11,12,13)
x3 <- 34
x4 <- c(100,110,120)
x5 <- c(50,51)
myfit <- s$kdlorfit(x1,x2,x3,x4,x5)
scalaType(myfit)
identical(x1,myfit(0L)$"asInstanceOf[Array[Double]]"())
identical(x3,myfit(2L)$"asInstanceOf[Double]"())
Note the need to cast using asInstanceOf because the Scala type of myfit is Array[Any].
If the function returned Array[Array[Double]] instead of Array[Any], no casting would be needed, as shown below.
s + '
def kdlorfit2(
projectedTrainToMatrix: Array[Double],
predictedTrain: Array[Double],
kernelParam: Array[Double],
projection: Array[Double],
thresholdsToArray: Array[Double]) =
{
Array(projectedTrainToMatrix,predictedTrain,kernelParam,projection,thresholdsToArray)
}
'
myfit <- s$kdlorfit2(x1,x2,I(x3),x4,x5)
scalaType(myfit)
identical(x1,myfit(0L))
identical(x3,myfit(2L))
Note that, when calling kdlorfit2, the argument x3 is passed as Array[Double] because it is wrapped in I(). Without wrapping, it is a passed as a Double as in the previous example.

F# scan a buffer finding the last part that begins \c\f and not followed by comma

Trying to find an elegant F# solution for this. I'm reading 1000 bytes from a file into a buffer, "buff". That part is easy.
Now, I want to scan the buffer looking for the last occurrence of a two-character combination:
Either a carriage return ('\r') or a line feed ('\f') that is not followed by a comma.
When I've found that, I need to find the next CR or LF (or the end of the buffer) and print the contents in between as a string.
Context: The file is a CSV file and I want the last line that has some non-empty value in the first column.
First of all, if you are reading CSV files, then it might be better idea to use CSV type provider. This gives you a nice typed access to CSV files and it has a couple of options that you can use for dealing with messy CSV files (e.g. if you need to skip a few lines). Alternatively, the F# Data library also has CSV parser, which lets you read the file using untyped API.
That said, if you really want to implement parsing on your own, then the following example should illustrate the idiomatic approach. I'm not sure I understand your problem exactly, but say we have:
let input = "start \r body \r, comma"
let buff = input.ToCharArray()
I believe you want to find the region between \r and \r,. You can do this using a recursive function that remembers the end of the range and the start of the range and decrements the starting range as it iterates over the string. You can use pattern matching to detect the cases that you need:
let rec findRange startLoc endLoc =
if startLoc < 0 then failwith "reached beginning"
match buff.[startLoc], buff.[startLoc+1] with
| ('\r' | '\f'), ',' -> findRange (startLoc - 1) startLoc
| ('\r' | '\f'), _ -> startLoc, endLoc
| _, _ -> findRange (startLoc - 1) endLoc
Using this, we can now get the range and get the required substring:
let s, e = findRange (buff.Length-2) (buff.Length-1)
input.Substring(s + 1, e - s - 1)
Elegant is in the eye of the beholder but one approach is implementing a matcher type. A matcher is function that given an input string and a position either succeeds returning a new matcher state with an updated position or fails.
// A matcher state holds a string and the position
[<Struct>]
type MatcherState =
{
Input : string
Pos : int
}
static member New i p : MatcherState = { Input = i ; Pos = p }
member x.Reposition p : MatcherState = { Input = x.Input ; Pos = p }
member x.AdvanceBy i : MatcherState = { Input = x.Input ; Pos = x.Pos + i }
member x.Current = x.Input.[x.Pos]
member x.InRange = x.Pos >= 0 && x.Pos < x.Input.Length
member x.Eos = x.Pos >= x.Input.Length
// A Matcher is a function that given a MatcherState
// returns Some MatcherState with a new position if successful
// otherwise returns None
type Matcher = MatcherState -> MatcherState option
By defining a few active patterns we can pattern match for the line start:
// Matches a line start
let mlineStart =
fun ms ->
match ms with
// Bad cases, new line followed by WS + Comma
| Cr (Ln (Ws (Comma _ | Eos _)))
| Ln (Ws (Comma _ | Eos _)) -> mbad
// Good cases, new line not followed by WS + Comma
| Cr (Ln (Ws ms))
| Ln (Ws ms) -> mgood ms
// All other cases bad
| _ -> mbad
Note: I handle new line followed by whitespace + comma here.
The line end is matched similar:
// Matches a line end
let mlineEnd =
fun ms ->
match ms with
// Good cases, new line or EOS
| Cr (Ln ms)
| Ln ms
| Eos ms -> mgood ms
// All other cases bad
| _ -> mbad
Finally we scanBackward looking for the line start and if we find it scanForward from that position until we find the line end.
match scanBackward testCase testCase.Length mlineStart with
| None -> printfn "No matching line start found"
| Some startPos ->
// Scan forwards from line start until we find a line end
match scanForward testCase startPos mlineEnd with
| None -> printfn "Line start found #%d, but no matching line end found" startPos
| Some endPos ->
let line = testCase.Substring (startPos, endPos - startPos)
printfn "Line found: %s" line
Matcher is actually a simplistic parser but that produces no values and that support scanning forward and backwards. The approach I have chosen is not the most efficient. If efficiency is important it can be improved by applying parser combinator techniques used by for example FParsec.
Hope this was interesting. I am sure someone can up with a shorter regex solution but what fun is that?
Full example follows (no quality guarantees given, use it as an inspiration)
// A matcher state holds a string and the position
[<Struct>]
type MatcherState =
{
Input : string
Pos : int
}
static member New i p : MatcherState = { Input = i ; Pos = p }
member x.Reposition p : MatcherState = { Input = x.Input ; Pos = p }
member x.AdvanceBy i : MatcherState = { Input = x.Input ; Pos = x.Pos + i }
member x.Current = x.Input.[x.Pos]
member x.InRange = x.Pos >= 0 && x.Pos < x.Input.Length
member x.Eos = x.Pos >= x.Input.Length
// A Matcher is a function that given a MatcherState
// returns Some MatcherState with a new position if successful
// otherwise returns None
type Matcher = MatcherState -> MatcherState option
let mgood ms = Some ms
let mbad = None
// Matches EOS
let meos : Matcher =
fun ms ->
if ms.Eos then
mgood ms
else
mbad
// Matches a specific character
let mch ch : Matcher =
fun ms ->
if not ms.InRange then
mbad
elif ms.Current = ch then
mgood <| ms.AdvanceBy 1
else mbad
// Matches zero or more whitespaces
let mws : Matcher =
fun ms ->
let rec loop pos =
if pos < ms.Input.Length then
let ch = ms.Input.[pos]
if ch = ' ' then
loop (pos + 1)
else
mgood <| ms.Reposition pos
else
mgood <| ms.Reposition pos
loop (max ms.Pos 0)
// Active patterns
let (|Eos|_|) = meos
let (|Comma|_|) = mch ','
let (|Cr|_|) = mch '\r'
let (|Ln|_|) = mch '\n'
let (|Ws|_|) = mws
// Matches a line start
let mlineStart =
fun ms ->
match ms with
// Bad cases, new line followed by WS + Comma
| Cr (Ln (Ws (Comma _ | Eos _)))
| Ln (Ws (Comma _ | Eos _)) -> mbad
// Good cases, new line not followed by WS + Comma
| Cr (Ln (Ws ms))
| Ln (Ws ms) -> mgood ms
// All other cases bad
| _ -> mbad
// Matches a line end
let mlineEnd =
fun ms ->
match ms with
// Good cases, new line or EOS
| Cr (Ln ms)
| Ln ms
| Eos ms -> mgood ms
// All other cases bad
| _ -> mbad
// Scans either backward or forward looking for a match
let scan steps input pos (m : Matcher) =
let rec loop ms =
match m ms with
| Some mms ->
if steps < 0 then
Some mms.Pos
else
Some ms.Pos
| None ->
if steps = 0 then
None
elif steps > 0 && ms.Pos >= ms.Input.Length then
None
elif steps < 0 && ms.Pos < 0 then
None
else
loop <| ms.AdvanceBy steps
loop (MatcherState.New input (min input.Length (max 0 pos)))
let scanForward = scan 1
let scanBackward = scan -1
[<EntryPoint>]
let main argv =
// Some test cases
let testCases =
[|
"""1,2,3,4
4,5,6,7"""
"""1,2,3,4
4,5,6,7
"""
"""1,2,3,4
4,5,6,7
,2,3,4
"""
"""1,2,3,4
4,5,6,7
,2,3,4
"""
|]
for testCase in testCases do
// Scan backwards from end until we find a line start
match scanBackward testCase testCase.Length mlineStart with
| None -> printfn "No matching line start found"
| Some startPos ->
// Scan forwards from line start until we find a line end
match scanForward testCase startPos mlineEnd with
| None -> printfn "Line start found #%d, but no matching line end found" startPos
| Some endPos ->
let line = testCase.Substring (startPos, endPos - startPos)
printfn "Line found: %s" line
0

multi-directional infinte sequence - ML

I want to use the datatype sequence that is defined as follows:
datatype 'a seq = Nil | Cons of 'a * (unit-> 'a seq);
exception EmptySeq;
fun head(Cons(x,_)) = x | head Nil = raise EmptySeq;
fun tail(Cons(_,xf)) = xf() | tail Nil = raise EmptySeq;
which has to option to iterate over functions backward and forward:
datatype direction = Back | Forward;
datatype 'a bseq = bNil | bCons of 'a * (direction -> 'a bseq);
and i defined those as well:
fun bHead(bCons(x,_)) = x | bHead bNil = raise EmptySeq;
fun bForward(bCons(_,xf)) = xf(Forward) | bForward bNil = raise EmptySeq;
fun bBack(bCons(_,xf)) = xf(Back) | bBack bNil = raise EmptySeq;
Now, what I'm trying to do is to create a function "create_seq" that gets an int "k" and returns an infinte sequence which can be iterated back and forth.
for example:
- create_seq 2;
val it = bCons (2,fn) : int bseq
- bForward it;
val it = bCons (3,fn) : int bseq
- bForward it;
val it = bCons (4,fn) : int bseq
- bBack it;
val it = bCons (3,fn) : int bseq
- bBack it;
val it = bCons (2,fn) : int bseq
- bBack it;
val it = bCons (1,fn) : int bseq
- bBack it;
val it = bCons (0,fn) : int bseq
- bBack it;
val it = bCons (~1,fn) : int bseq
this is what I've been trying to do and can't figure out why it doesn't work:
fun create_seq k = (k,fun check Forward = create_seq(k+1)
| check Back = create_seq(k-1));
nor this:
fun create_seq k = (k,fn x => case x of Forward => create_seq(k+1)
| Back => create_seq(k-1));
or even this:
fun create_seq k = (k,fn Forward => create_seq(k+1)
| Back => create_seq(k-1));
It seems I forgot the constructor:
fun intbseq(k:int) = bCons(k,fn Forward => intbseq(k+1)| Back => intbseq(k-1));
this should work.

ML can't unify 'a with int

The exercise is to code a function in ML that deletes an element from a binary search tree.
Here's the code:
datatype 'a tree = Lf | Br of 'a * 'a tree * 'a tree;
fun deleteTop (Br(_, Lf, t2)) = t2
| deleteTop (Br(_, t1, Lf)) = t1
| deleteTop (Br(_, Br(v, u1, u2), t2)) =
Br(v, deleteTop (Br(v, u1, u2)), t2);
fun delete (Lf, k : string) = Lf
| delete (Br((a,b),t1,t2), k) =
if a=k then deleteTop(Br((a,b),t1,t2))
else if k<a then Br((a,b),delete(t1,k),t2)
else Br((a,b),t1,delete(t2,k));
When I load this into Poly/ML it warns me of incomplete pattern matching in deleteTop but that doesn't matter because delete only ever passes deleteTop a branch.
val deleteTop = fn: 'a tree -> 'a tree
val delete = fn: (string * 'a) tree * string -> (string * 'a) tree
I created a (string * int) tree and ran
> delete(a,"they");
Error-Type error in function application.
Function: delete : (string * 'a) tree * string -> (string * 'a) tree
Argument: (a, "they") : (string * int) tree * string
Reason:
Can't unify (string * 'a) tree with (string * int) tree
(Different type constructors)
Found near delete (a, "they")
Static Errors
Let me re-iterate one of those lines:
Can't unify (string * 'a) tree with (string * int) tree
Why can't ML unify 'a with int?
You can get a message like that if you have redefined tree and delete at the top level since you defined a. It's complaining that the tree in a is not the same as the tree in delete.
For example
> datatype 'a t = T of 'a;
datatype 'a t = T of 'a
> val x = T 1;
val x = T 1: int t
> datatype 'a t = T of 'a;
datatype 'a t = T of 'a
> val T y = x;
Pattern and expression have incompatible types.
Pattern: T y : 'a t
Expression: x : int t
Reason: Can't unify 'a t with int t (Different type constructors)
Found near val T y = x
Static Errors
>

How to use a self made Type in F#?

I made a type, but I don't know how to use it properly and I don't found any solution on google.
type Sample =
{
TrackPosition : int
TubePosition : int
Barcode : string
}
let arraySamples = Array.create Scenario.Samples.NumberOfSamples **Sample**
BarcodeGenerieren.Samples.Sample
let mutable trackPosition = Scenario.Samples.StartTrackPositions
let mutable index = 1
for i in 1 .. Scenario.Samples.NumberOfSamples do
let randomNumber = System.Random().Next(0,9999)
if index > 24 then
trackPosition <- trackPosition + 1
index <- 1
arraySamples.[index] <- **new Sample{TrackPosition= trackPosition, TubePosition = index, Barcode = sprintf "100%s%06d" ((trackPosition + 1) - Scenario.Samples.StartTrackPositions) randomNumber}**
So my question is, what should I changed so that it works, when I will give the type of the array and when I will give the sample with data to the array?
You have created what is referred to as a record type. You can initialise it with the following syntax
{TrackPosition = 0;TubePosition = 0;Barcode = "string"}
your syntax in the last line is almost correct - it should be
arraySamples.[index] <- Sample{
TrackPosition= trackPosition;
TubePosition = index;
Barcode = sprintf "100%s%06d" ((trackPosition + 1) - Scenario.Samples.StartTrackPositions) randomNumber}
The changes are
Eliminate new
replace , with ;

Resources