I'm writing a binary search implementation. The problem I have is with a pattern matching block.
This code using pattern matching returns weird results. The first match block does not return what I expect. It warns me that (_,_) is never reached.
let binSearch (item:double) (arr:list<double>) =
let rec binSearchRec first last =
if first > last then
let lastIndex = arr.Length-1
let len = arr.Length
match (first, last) with
| (0, -1) -> System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
| (len, lastIndex) -> System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
| (_,_) -> System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])
else
let mid = (first+last)/2
match item.CompareTo(arr.[mid]) with
| -1 -> binSearchRec first (mid-1)
| 0 -> "CONTAINS"
| 1 -> binSearchRec (mid+1) last
binSearchRec 0 (arr.Length-1)
Replacing that first match (first, last) call with this if-else alternative works well:
if first = 0 && last = -1 then
System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
else if first = len && last = lastIndex then
System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
else
System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])
I don't understand how that match call is different from this if-else call and why this works well but the pattern matching block does not.
A weird result is that printing len in the (len, lastIndex) match returns wrong numbers inside the match. For an array of length three a print of len before the match statement will show 3 whereas a print inside the match will show 1.
One of your branch in match expression is creating new bindings to existing symbols
| (len, lastIndex) -> ...
so this branch matches with every other case.
If you what to match against existing values in match expression you can use when clase for that:
| (a, b) when a = len && b = lastIndex -> ...
Another option would be declaring len and lastIndex as literals to use them in pattern matching but it seems not natural in your case.
[<Literal>]
let len = arr.Length
Related
I have the following line:
| ResponseTableTypes.Order ->
orderProcessor.ProcessEvent action message
orderEvent.Trigger()
since I have a lot of entries, for layout reasons, I did:
| ResponseTableTypes.Order -> orderProcessor.ProcessEvent action message; orderEvent.Trigger()
all good, but then I added some return type:
| ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s)
that will not compile, I get:
The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.
so, if I break down the line again:
| ResponseTableTypes.Order ->
let s = orderProcessor.ProcessEvent action message
orderEvent.Trigger(s)
then it obviously works again
what is happening with the let/semicolon combination?
I will answer your question, but in doing so answer a more important question of how to ask a question.
Starting with | ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s), let's reduce irrelevancies such as tables, orders, and events:
let result =
let s = expression; action
Now let's ascribe simple values to the names, so that apart from the issue we want to identify, it should compile.
let x =
let y = 0; 0
// FS0588 the block following this let is unfinished.
// FS0020 The result of this expression has type 'int' and is implicitly ignored.
Now that we have a clean question, we can start to answer it, but this is the easy part. let y = 0; 0 is equivalent to let y = (0;0) and so the first 0 is being ignored, and since let y = ... is an incomplete expression which does not return anything, there is nothing to ascribe to x.
There is an antique syntax let y = 0 in 0 which does allow merging multiple lines with lets into one.
I'm trying to implement a linked list in f# using records. I know I can use the build in list type but this is for learning purposes. My type is:
type Cell = { data : int; next : RList}
and RList = Cell option ref
And I'd like to make a simple insert function, but I'm told that f# is expecting a boolean but was given an expression of type unit. I'm wondering if this means I've formatted my if/else statement incorrectly
let rec insert comp (item: int) (list: RList) =
let c = {data = item; next = ref None}
match !list with
| None -> list = cellToRList c
| Some {data = d; next = remaining} ->
if (comp(item, d)) then
c.next := !remaining
remaining := ref c (* compiler indicates error here *)
else insert comp item remaining
Note: comp is any comparison function taking (item, d) as input and outputting true or false ex:
let compare (x, y) = x > y
My goal is simply to insert a new cell with data = item if compare outputs true. In the example above it could be used to insert into a sorted list and maintain sorted-ness. The entire function should return type unit. Any hint as to why my interpreter is looking for a boolean would be appreciated!
Note: I'm very new to F#
====
Fixed with improvements Courtesy of Foggy, Mikhail, and Fyodor
type Cell = { data : int; next : (Cell option) ref}
let rec insert compare (item: int) (list: (Cell option) ref) : unit =
let c = {data = item; next = ref None}
match !list with
| None -> list := Some c
| Some {data = d; next = remaining} ->
if (compare(d, item)) then
c.next := !remaining
remaining := Some c
else insert compare item remaining
You return a bool from your None match:
| None -> list = cellToRList c
Equals sign is a comparison operator here. So the compiler infers the function to return bool, while I guess your intention is to return unit.
In any case, whenever you don't understand the inferred types of your functions, try annotating them explicitly. In your case, make it
let rec insert comp (item: int) (list: RList) : unit =
And you will see the problem that I described above.
You may want to remove type annotation once everything compiles.
I am working on a function that pattern matches some of my user-defined types in f# and converts them to strings. Part of the code looks like the following:
let gsToString (gs : general_structure) : string =
match gs with
| Date(Scattered(Eom(Ascending))) -> "Date(Scattered(Eom(Ascending)))"
| Date(Scattered(Eom(SameDate(dt)))) -> "Date(Scattered(Eom(SameDate(" + dt.ToString() + "))))"
| Number(AllNegative(Int1(Neither))) -> "Number(AllNegative(Int1(Neither)))"
| Number(AllNegative(Int1(SameInt(si)))) -> "Number(AllNegative(Int1(SameFloat(" + si.ToString() + "))))"
There are many other types being matched in this function, but these should be enough to convey the issue. Additionally, the types causing problems are:
| SameDate of System.DateTime
| SameFloat of float
Obviously, It is pretty trivial to do the first pattern matching function that converts my general_structure types to strings. However, a problem arises in my next function (which needs to be called later on in the code), where I need to reconvert the string representation back to a general_structure. The problem areas look like the following:
let stringToGS (str : string) : general_structure =
match str with
| "Date(Scattered(Eom(Ascending)))" -> Date(Scattered(Eom(Ascending)))
| "Date(Scattered(Eom(SameDate(dt))))"-> Date(Scattered(Eom(SameDate(System.DateTime.Parse dt))))
| "Number(AllNegative(Int1(Neither)))" -> Number(AllNegative(Int1(Neither)))
| "Number(AllPositive(Float1(SameFloat(sf))))" -> Number(AllPositive(Float1(SameFloat((float) sf))))
Although the first and the third cases in the stringToGS function work just fine, I am unable to find a way to convert the others back to their original form. If there any way to take a string inside of a pattern matching statement (in this case it would be dt and fs) and somehow parse only that portion of the pattern in order to return a different value (in this case I am trying to make them System.DateTimes and Floats, respectively) and return then to their original forms of:
Date(Scattered(Eom(SameDate(dt))))
Number(AllPositive(Float1(SameFloat(sf))))
? I would appreciate any help.
EDIT:
I was able to resolve the problem by doing something like the following with if statements for the cases that were causing problems:
if str.Contains("Scattered(Eom(SameDate")
then
let p1 = str.IndexOf(")")
let p2 = str.LastIndexOf("(")
let dt1 = str.Remove(p1)
let dt2 = dt1.Substring(p2 + 1)
let date = System.DateTime.Parse dt2
Date(Scattered(Eom(SameDate(date))))
Then, I could just do the normal pattern matching on all of the types that did not contain nested data.
You could also use active patterns, if there is a limited amount of classes and you don't want to use a serialization library:
open System
let (|RegexMatch|_|) pattern input =
let matches = System.Text.RegularExpressions.Regex.Matches(input, pattern)
if matches.Count = 1 then Some matches.[0].Groups.[1].Value
else None
type GeneralStructure =
| NoPayload
| DatePayload of DateTime
| StringPayload of string option
let toString = function
| NoPayload -> "NoPayload"
| DatePayload dt -> sprintf "DatePayload(%d)" <| dt.ToBinary()
| StringPayload None -> "StringPayload(None)"
| StringPayload (Some s) -> sprintf "StringPayload(Some(%s))" s
let fromString = function
| "NoPayload" -> NoPayload
| "StringPayload(None)" -> StringPayload None
| RegexMatch #"DatePayload\((.*)\)" dt -> DatePayload <| DateTime.FromBinary(Int64.Parse dt)
| RegexMatch #"StringPayload\(Some\((.*)\)\)" msg -> StringPayload <| Some msg
| o -> failwithf "Unknown %s %s" typeof<GeneralStructure>.Name o
let serialized = StringPayload <| Some "Foo" |> toString
let deserialized = fromString serialized
let serialized' = DatePayload DateTime.UtcNow |> toString
let deserialized' = fromString serialized'
// val serialized : string = "StringPayload(Some(Foo))"
// val deserialized : GeneralStructure = StringPayload (Some "Foo")
// val serialized' : string = "DatePayload(5247430828937321388)"
// val deserialized' : GeneralStructure = DatePayload 06.08.2015 18:04:10
Note that the regex is not foolproof, I made that up just to fit these cases.
I'm looking for a functional (as in, non-imperative) implementation of StringBuilder or equivalent. I've seen a couple of functional arrays implementation, but they don't support insertion natively. Bonus for open-source, non-(L?A?)GPL, bonus for F#, but I can translate from Haskell/OCaml/SML if needed.
Suggestions for algorithms welcome.
StringBuilders advantage over string is due to minimizing allocations. It pre-allocates a buffer to avoid allocating for every insert/append. This requires mutability--some object must own (and mutate) the buffer.
Incidentally, System.String already fits (what I can make of) your description: it's immutable and supports concatenation, insertionMSDN, and removalMSDN.
UPDATE
Tomas' idea intrigued me. Taking his idea, here's what I came up with
type StringBuilder =
private
| Empty
| StringBuilder of int * string * int * StringBuilder
member this.Length =
match this with
| Empty -> 0
| StringBuilder(_, _, n, _) -> n
override this.ToString() =
let rec rev acc = function
| Empty -> acc
| StringBuilder(idx, str, _, bldr) -> rev ((idx, str)::acc) bldr
let buf = ResizeArray(this.Length)
for idx, str in rev [] this do buf.InsertRange(idx, str)
System.String(buf.ToArray())
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module StringBuilder =
let empty = Empty
let length (bldr:StringBuilder) = bldr.Length
let insert index str bldr =
if index < 0 || index > (length bldr) then invalidArg "index" "out of range"
StringBuilder(index, str, str.Length + bldr.Length, bldr)
let create str = insert 0 str empty
let append str bldr = insert (length bldr) str bldr
let remove index count (bldr:StringBuilder) = create <| bldr.ToString().Remove(index, count)
Usage
let bldr =
StringBuilder.create "abcdef"
|> StringBuilder.insert 1 "xyz"
|> StringBuilder.append "123"
|> StringBuilder.remove 1 2
bldr.ToString() //azbcdef123
It's persistent and insertion is O(1).
I don't know about any implementation that would do exactly what you want. However, I don't think you can ever get O(1) complexity of inserting (at arbitrary index) and O(n) complexity of iteration over the results.
If you're happy to sacrifice the complexity of insertion, then you can use just string as Daniel suggests. On the other side, if you're willing to sacrifice the complexity of toString, then you can make immutable data structure with O(1) insertion at any location by using a list of strings and indices:
type InsertList = IL of (int * string) list
// Insert string 'str' at the specified index
let insertAt idx str (IL items) = IL (idx, str)::items
// Create insert list from a string
let ofString str = IL [str]
The conversion to string is a bit more tricky. However, I think you can get O(n log n) complexity by using a mutable LinkedList and inserting individual characters at the right location by iterating over the insertions from the end. The use of LinkedList is going to be locallized to toString, so the data structure is still purely functional.
I am new to F# and I have this code:
if s.Contains("-") then
let x,y =
match s.Split [|'-'|] with
| [|a;b|] -> int a, int b
| _ -> 0,0
Notice that we validate that there is a '-' in the string before we split the string, so the match is really unnecessary. Can I rewrite this with Options?
I changed this code, it was originally this (but I was getting a warning):
if s.Contains("-") then
let [|a;b|] = s.Split [|'-'|]
let x,y = int a, int b
NOTE: I am splitting a range of numbers (range is expressed in a string) and then creating the integer values that represent the range's minimum and maximum.
The match is not unnecessary, the string might be "1-2-3" and you'll get a three-element array.
Quit trying to get rid of the match, it is your friend, not your enemy. :) Your enemy is the mistaken attempt at pre-validation (the "if contains" logic, which was wrong).
I think you may enjoy this two-part blog series.
http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!180.entry
http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!181.entry
EDIT
Regarding Some/None comment, yes, you can do
let parseRange (s:string) =
match s.Split [|'-'|] with
| [|a;b|] -> Some(int a, int b)
| _ -> None
let Example s =
match parseRange s with
| Some(lo,hi) -> printfn "%d - %d" lo hi
| None -> printfn "range was bad"
Example "1-2"
Example "1-2-3"
Example "1"
where parseRange return value is a Some (success) or None (failure) and rest of program can make a decision later based on that.