This question already has answers here:
Shadowing and Nested function
(2 answers)
Closed 6 years ago.
This is a highly skeletonized version of a financial algorithm. There's a lot more logic in the actual conditions and data processing represented here by "myFunc"--which isn't really intended to make sense in this version.
My question is: how do I understand why the use of firstMultiple in this block is permissible and sensible. Why should it work?
The expression is mapped directly from the line marked A to the line marked C3 where its value is used. But then at C1 and C2--which are (roughly) the same level of "indentation" as C3--here firstMultiple is assigned--seemingly as if it were mutable-??
I guess I don't understand why C3 uses firstMultiple while C1 can seemingly overwrite it. (The debugger, and running it, indicate that it's fine).
I'm hoping this question and example might elicit some insight into how to think about (nested) scopes. (I'm glad of course to have other comments on the design as well, but keep in mind that this code is extremely stripped of a lot of analysis.) (And I may have made the algorithm illogical in my stripping of it, but I'm trying to focus on the question of scope.)
let rec ListBuilder factor firstMultiple useFirstMultiple inputList outputList = // "A"
match inputList with
| [] -> []
| h::[] -> List.rev (inputList.Head :: outputList)
| _ ->
let nextInput = inputList.Head
let newOutputList, remInputList, firstMultiple = // "B"
match outputList with
| [] -> //first pass, capture firstMultiple now
let firstMultiple = nextInput * factor // "C1"
[nextInput], inputList.Tail, firstMultiple // "C2"
| _ ->
let lastOutput = outputList.Head
let multiple =
if useFirstMultiple then firstMultiple // "C3"
else lastOutput * factor
let newOutputList =
if (myfunc multiple nextInput: bool) then
nextInput :: outputList
else
outputList
let remInputList =
if not (myfunc multiple nextInput: bool) then
inputList.Tail
else
inputList
newOutputList, remInputList, firstMultiple
ListBuilder factor firstMultiple useFirstMultiple remInputList newOutputList
As this example is basically a loop of
let rec ListBuilder
...
ListBuilder
the loop hits C3 for every item in outputlist and then when outputlist is empty finally hits C1 and C2
At C3 firstMultiple is only read.
then firstMultiple // "C3"
At C1 and C2, firstMultiple is bound then read, notice I said bound not set or mutated
let firstMultiple = nextInput * factor // "C1"
[nextInput], inputList.Tail, firstMultiple // "C2"
At C1 firstMultiple is not the same variable as firstMultiple at A or B or C3, it is a new variable. So when you think that it is mutating the firstMultiple at the location of C3 it is not.
If your example conversion is correct then you could convert the code to this:
let temp = nextInput * factor // "C1"
[nextInput], inputList.Tail, temp // "C2"
or more simply
[nextInput], inputList.Tail, (nextInput * factor) // "C2"
In this example firstMultiple at C1 and C2 is just a reused variable name and because of shadowing is allowed, but not needed.
EDIT
The OP asked in a comment the further question:
why line "B" takes firstMultiple from "C2" and not from "A".
The reason is that line B is a tuple of three values which are generated by the result of the expressions following line B. All of this are the expressions that creates the three values for the tuple.
let newOutputList, remInputList, firstMultiple = // "B"
match outputList with
| [] -> //first pass, capture firstMultiple now
let firstMultiple = nextInput * factor // "C1"
[nextInput], inputList.Tail, firstMultiple // "C2"
| _ ->
let lastOutput = outputList.Head
let multiple =
if useFirstMultiple then firstMultiple // "C3"
else lastOutput * factor
let newOutputList =
if (myfunc multiple nextInput: bool) then
nextInput :: outputList
else
outputList
let remInputList =
if not (myfunc multiple nextInput: bool) then
inputList.Tail
else
inputList
newOutputList, remInputList, firstMultiple
The two lines that generate the three tuple values depending on the match result are
[nextInput], inputList.Tail, firstMultiple // "C2"
and
newOutputList, remInputList, firstMultiple
Line B is not a function with firstMultiple as a parameter, e.g.
let myFunc firstMultiple = ...
it is a match function that returns a tuple of three values
let newOutputList, remInputList, firstMultiple = // "B"
firstMultiple is not being passed in via B
but being created as a new variable and bound at C1
let firstMultiple = nextInput * factor // "C1"
and then returned via C2
[nextInput], inputList.Tail, firstMultiple // "C2"
Inner scopes can capture variables in outer scopes. I assume your question means that you were expecting an error when assigning a new value. There is a difference between shadowing and actual mutable variables. See these two examples.
Here the x is not actual mutable, though it feels like it:
let testValue (l: int list) =
let x = l.[0]
printfn "%A" x
do
let x= l.[1]
printfn "%A" x
printfn "%A" x
let x = l.[2]
printfn "%A" x
Here x is actually mutable:
let testValue2 (l: int list) =
let mutable x = l.[0]
printfn "%A" x
x <- l.[1]
printfn "%A" x
Try it with testValue [1;2;3]
Related
Try to play with string and I have string like: "Hello.Word" or "stackOver.Flow"
and i what first char convert to lower case: "hello.word" and "stackOver.flow"
For snakeCase it easy we need only change UpperCase to lower and add '_'
but in camelCase (with firs char in lower case) i dont know how to do this
open System
let convertToSnakeCase (value:string) =
String [|
Char.ToLower value.[0]
for ch in value.[1..] do
if Char.IsUpper ch then '_'
Char.ToLower ch |]
Who can help?
module Identifier =
open System
let changeCase (str : string) =
if String.IsNullOrEmpty(str) then str
else
let isUpper = Char.IsUpper
let n = str.Length
let builder = new System.Text.StringBuilder()
let append (s:string) = builder.Append(s) |> ignore
let rec loop i j =
let k =
if i = n (isUpper str.[i] && (not (isUpper str.[i - 1])
((i + 1) <> n && not (isUpper str.[i + 1]))))
then
if j = 0 then
append (str.Substring(j, i - j).ToLower())
elif (i - j) > 2 then
append (str.Substring(j, 1))
append (str.Substring(j + 1, i - j - 1).ToLower())
else
append (str.Substring(j, i - j))
i
else
j
if i = n then builder.ToString()
else loop (i + 1) k
loop 1 0
type System.String with
member x.ToCamelCase() = changeCase x
printfn "%s" ("StackOver.Flow".ToCamelCase()) //stackOver.Flow
//need stackOver.flow
I suspect there are much more elegant and concise solutions, I sense you are learning functional programming, so I think its best to do stuff like this with recursive function rather than use some magic library function. I notice in your question you ARE using a recusive function, but also an index into an array, lists and recursive function work much more easily than arrays, so if you use recursion the solution is usually simpler if its a list.
I'd also avoid using a string builder, assuming you are learning fp, string builders are imperative, and whilst they obviously work, they wont help you get your head around using immutable data.
The key then is to use the pattern match to match the scenario that you want to use to trigger the upper/lower case logic, as it depends on 2 consecutive characters.
I THINK you want this to happen for the 1st char, and after a '.'?
(I've inserted a '.' as the 1st char to allow the recursive function to just process the '.' scenario, rather than making a special case).
let convertToCamelCase (value : string) =
let rec convertListToCamelCase (value : char list) =
match value with
| [] -> []
| '.' :: second :: rest ->
'.' :: convertListToCamelCase (Char.ToLower second :: rest)
| c :: rest ->
c :: convertListToCamelCase rest
// put a '.' on the front to simplify the logic (and take it off after)
let convertAsList = convertListToCamelCase ('.' :: (value.ToCharArray() |> Array.toList))
String ((convertAsList |> List.toArray).[1..])
The piece to worry about is the recusive piece, the rest of it is just flipping an array to a list and back again.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
My task is:
Implement the function puzz. It should simulate the game similar to 15 Puzzle. In our case, we have 25 squares, where 24 squares are occupied by tiles with big case letters from 'A' to 'X'. One tile is free and is denoted by ' '. In each move, you can move a tile (denoted by its letter) into the free space. The function gets the original configuration and a sequence of valid moves. It should output the resulting configuration.
I am new to Haskell, I can only do one first move.
Result after the last move must be ["ABCDE", "FGHIJ", "KLMNO", "PQRST ", "UVWX_"]. How to save the result of the first move and use it to do the second move, and the next, and then iterate some more?
s1 = ["AC DE",
"FBHIJ",
"KGLNO",
"PQMRS",
"UVWXT"]
p1 = "CBGLMRST"
puzz :: Result -> [Char] -> Result
puzz s1 p1 =
let i = 0
p = p1 !! i
change r = [ if c == ' ' then p else if c == p then ' ' else c | c <- r ]
out = [ change r | r <- s1 ]
in out
The s1 and the p1 in the puzz s1 p1 aren't your constants s1 and p1. They are only templates. For example puzz [" B"] "B" returns ["BB "] and p1 becomes [" B"] and s1 becomes "B" in that function call.
Don't try iterate (I removed part of code with the i). Use recursion. There are no variables in Haskell, only constants and input parameters. Input parameter (represented by the template) should be in each call different (closer to the end) because of referential integrity.
Don't forget to finish the algorithm.
(p:p1) - Template of input parameter which says that there is a nonempty list and the first character will be p and tail will be p1.
puzz s1 [] = s1 - When second parametr is empty list, then return first parameter (end).
puzz out p1 - Calling puzz for the changed s1 as out and p1 from (p:p1) (recursion).
s1 = ["AC DE","FBHIJ","KGLNO","PQMRS","UVWXT"]
p1 = "CBGLMRST"
puzz :: [String] -> [Char]-> [String]
puzz s1 (p:p1) = let
change r = [ if c == ' ' then p else if c == p then ' ' else c | c <- r ]
out = [ change r | r <- s1 ]
in puzz out p1
puzz s1 [] = s1
Output:
puzz s1 p1
=> ["ABCDE","FGHIJ","KLMNO","PQRST","UVWX "]
I have been trying to create a filter that checks if a phrase in a list of phrases exists in the text using recursive functions and match patterns, but somehow that does not seems to work... Maybe someone could give me hint why?
let rec matchTails (tail1 : string list) (tail2 : string list) =
match tail1, tail2 with
| h1::t1 , h2::t2 ->
if (h1=h2) then
matchTails t1 t2
else
false
| _, [] -> false
| [],_-> true
let rec check2 (textH: string) (textT: string list) (phrases: string list list) =
match phrases with
|[] -> ()
| h :: t ->
printfn "%s -- %s" (h.Head) (textH)
match h with
|x when x.Length = 1 && x.Head = textH ->
()
|x when x.Head = textH && (matchTails (textT) (x)) ->
printfn "%s" (x.Head)
| _ -> ()
check2 (textH) (textT) (t)
let rec check (phrases : string list list) (text:string list) =
match text with
| [] -> ()
| h :: t ->
check2 (h) (t) (phrases)
check phrases t
let p = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
Function call: check p t
I have edited my question with fixing few mistakes, but however, with these lists the program is giving unit() as an output...
There are some hints:
matchTails returns incorrect result for
matchTails [ "asdf1" ] [ "asdf" ] => true
matchTails [ "asdf" ] [ "asdf"; "asdf1" ] => true
matchTails [ ] [ "" ] => true
I suspect it should return false in all these cases. Probably the implementation you want is:
let rec matchTails (phrase : string list) (text : string list) =
match phrase, text with
| h1 :: t1, h2 :: t2 -> if h1 = h2 then matchTails t1 t2
else false
| [ ], _ -> true
| _ -> false
let matchTails_test () =
if not (matchTails [ "" ] [ "" ]) then raise Exception()
...
check2 is not called recursively so only the first phrase is checked
check is not called recursively, it calls check2 and returns
Generally, try to decompose problem into smaller functions and test each of them separately. You are moving in right direction, what is missing is clarity of what the each of the functions should do and test cases.
Update:
Note that check2 does not really return any value (it returns unit). Also it functionality overlaps with matchTails - it checks the head with the first word in the phrase, it is what matchTails does anyway.
check also returns unit, () means unit.
So let's rewrite check:
let rec check (phrases : string list list) (text : string list) =
if phrases |> List.exists (fun ph -> matchTails ph text) then
true
else
match text with
| [] -> false
| _ :: tail -> check phrases tail
While the question has now been basically answered, I would like to point out that its division into sub-problems is already very sufficient; shockingly lacking are the associated testing, and some descriptive naming of the individual functions tackling each sub-problem.
What about naming (and testing) matchTails, check2 and check exemplarily like this?
let ps = [["rolex"]; ["free"; "spins"; "everyday"]; ["free"; "cash"]]
let t = ["hello";"and";"welcome";"to";"our";"annual";"free";"cash";"and";"rolex";"giveaway"]
startsWithPhrase ["hello"; "and"] t
containsPhrase ["free"; "cash"] t
containsAnyPhrase ps t
Spoiler:
let rec startsWithPhrase phrase text =
match phrase, text with
| h1::t1, h2::t2 when h1 = h2 -> startsWithPhrase t1 t2
| [], _-> true
| _ -> false
let rec containsPhrase phrase text =
startsWithPhrase phrase text ||
match text with
| _::tl -> containsPhrase phrase tl
| [] -> false
let rec containsAnyPhrase phrases text =
match phrases with
| h::tl ->
containsPhrase h text ||
containsAnyPhrase tl text
| [] -> false
It may be much easier to stay completely with high-level functions, each in place of one recursive loop. Albeit here with a slighty different approach, dividing your haystack into needle-sized slices and comparing each of them with a given phrase.
let containsPhraseHL phrase text =
Seq.windowed (List.length phrase) text
|> Seq.exists (Seq.forall2 (=) phrase)
containsPhraseHL ["free"; "cash"] t
let containsAnyPhraseHL phrases text =
List.exists (fun phrase -> containsPhraseHL phrase text) phrases
containsAnyPhraseHL ps t
How could one count how many times a substring exists within a string?
I mean if you have a String "one, two, three, one, one, two" how could you make it count "one" being present 3 times?
I thought String.Contains would be able to do the job but that only checks if the substring is present at all. String.forall is for chars and therefofre niether an option.
So i am really at a complete halt here. Can some enligten me?
You can use Regex.Escape to turn the string you're searching for into a regex, then use regex functions:
open System.Text.RegularExpressions
let countMatches wordToMatch (input : string) =
Regex.Matches(input, Regex.Escape wordToMatch).Count
Test:
countMatches "one" "one, two, three, one, one, two"
// Output: 3
Here's a simple implementation that walks through the string, using String.IndexOf to skip through to the next occurrence of the substring, and counts up how many times it succeeds.
let substringCount (needle : string) (haystack : string) =
let rec loop count (index : int) =
if index >= String.length haystack then count
else
match haystack.IndexOf(needle, index) with
| -1 -> count
| idx -> loop (count + 1) (idx + 1)
if String.length needle = 0 then 0 else loop 0 0
Bear in mind, this counts overlapping occurrences, e.g., subtringCount "aa" "aaaa" = 3. If you want non-overlapping, simply replace idx + 1 with idx + String.length needle.
Create a sequence of tails of the string to search in, that is, all substring slices anchored at its end. Then you can use forall functionality to determine the number of matches against the beginning of each of them. It's just golfier than (fun s -> s.StartsWith needle).
let count needle haystack =
[ for i in 0..String.length haystack - 1 -> haystack.[i..] ]
|> Seq.filter (Seq.forall2 (=) needle)
|> Seq.length
count "aba" "abacababac"
// val it : int = 3
a fellow student of mine came up with the so far simpelst solutions i have seen.
let countNeedle (haystack :string) (needle : string) =
match needle with
| "" -> 0
| _ -> (haystack.Length - haystack.Replace(needle, "").Length) / needle.Length
// This approach assumes the data is comma-delimited.
let data = "one, two, three, one, one, two"
let dataArray = data.Split([|','|]) |> Array.map (fun x -> x.Trim())
let countSubstrings searchTerm = dataArray |> Array.filter (fun x -> x = searchTerm) |> Array.length
let countOnes = countSubstrings "one"
let data' = "onetwothreeoneonetwoababa"
// This recursive approach makes no assumptions about a delimiter,
// and it will count overlapping occurrences (e.g., "aba" twice in "ababa").
// This is similar to Jake Lishman's answer.
let rec countSubstringFromI s i what =
let len = String.length what
if i + len - 1 >= String.length s then 0
else (if s.Substring(i, len) = what then 1 else 0) + countSubstringFromI s (i + 1) what
let countSubStrings' = countSubstringFromI data' 0 "one"
I want to extract the middle part of a string using FSharp if it is quoted, similar like this:
let middle =
match original with
| "\"" + mid + "\"" -> mid
| all -> all
But it doesn't work because of the infix operator + in pattern expression. How can I extract this?
I don't think there is any direct support for this, but you can certainly write an active pattern. Active patterns allow you to implement your own code that will run as part of the pattern matching and you can extract & return some part of the value.
The following is a pattern that takes two parameters (prefix and postfix string) and succeeds if the given input starts/ends with the specified strings. The pattern is not complete (can fail), so we'll use the |Name|_| syntax and it will need to return option value:
let (|Middle|_|) prefix postfix (input:string) =
// Check if the string starts with 'prefix', ends with 'postfix' and
// is longer than the two (meaning that it contains some middle part)
if input.StartsWith(prefix) && input.EndsWith(postfix) &&
input.Length >= (prefix.Length + postfix.Length) then
// Strip the prefix/postfix and return 'Some' to indicate success
let len = input.Length - prefix.Length - postfix.Length
Some(input.Substring(prefix.Length, len))
else None // Return 'None' - string doesn't match the pattern
Now we can use Middle in pattern matching (e.g. when using match):
match "[aaa]" with
| Middle "[" "]" mid -> mid
| all -> all
Parameterized active patterns to the rescue!
let (|HasPrefixSuffix|_|) (pre:string, suf:string) (s:string) =
if s.StartsWith(pre) then
let rest = s.Substring(pre.Length)
if rest.EndsWith(suf) then
Some(rest.Substring(0, rest.Length - suf.Length))
else
None
else
None
let Test s =
match s with
| HasPrefixSuffix("\"","\"") inside ->
printfn "quoted, inside is: %s" inside
| _ -> printfn "not quoted: %s" s
Test "\"Wow!\""
Test "boring"
… or just use plain old regular expression
let Middle input =
let capture = Regex.Match(input, "\"([^\"]+)\"")
match capture.Groups.Count with
| 2 -> capture.Groups.[1].Value
| _ -> input
Patterns have a limited grammar - you can't just use any expression. In this case, I'd just use an if/then/else:
let middle (s:string) =
if s.[0] = '"' && s.[s.Length - 1] = '"' && s.Length >= 2 then
s.Substring(1,s.Length - 2)
else s
If grabbing the middle of a string with statically known beginnings and endings is something that you'll do a lot, then you can always use an active pattern as Tomas suggests.
Not sure how efficient this is:
let GetQuote (s:String) (q:char) =
s
|> Seq.skip ((s |> Seq.findIndex (fun c -> c = q))+1)
|> Seq.takeWhile (fun c-> c <> q)
|> Seq.fold(fun acc c -> String.Format("{0}{1}", acc, c)) ""
Or there's this with Substring in place of the fold:
let GetQuote2 (s:String) (q:char) =
let isQuote = (fun c -> c = q)
let a = (s |> Seq.findIndex isQuote)+1
let b = ((s |> Seq.take(a) |> Seq.findIndex isQuote)-1)
s.Substring(a,b);
These will get the first instance of the quoted text anywhere in the string e.g "Hello [World]" -> "World"