I am trying to write a code to remove stopwords like "the", "this" in a string list etc.
I wrote this code:
let rec public stopword (a : string list, b :string list) =
match [a.Head] with
|["the"]|["this"] -> stopword (a.Tail, b)
|[] -> b
|_ -> stopword (a.Tail, b#[a.Head])
I ran this in the interactive:
stopword (["this";"is";"the"], []);;
I got this error:
This expression was expected to have type string list but here has type 'a * 'b
Match expressions in F# are very powerful, although the syntax is confusing at first
You need to match the list like so:
let rec stopword a =
match a with
|"the"::t |"this"::t -> stopword t
|h::t ->h::(stopword t)
|[] -> []
The actual error is due to the function expecting a tuple argument. You would have to call the function with:
let result = stopword (["this";"is";"the"], [])
Edit: since the original question was changed, the above answer is not valid anymore; the logical error in the actual function is that you end up with a single element list of which the tail is taken, resulting in an empty list. On the next recursive call the function chokes on trying to get the head of this empty list
The function in itself is not correctly implemented though and much more complicated than necessary.
let isNoStopword (word:string) =
match word with
| "the"|"this" -> false
| _ -> true
let removeStopword (a : string list) =
a |> List.filter(isNoStopword)
let test = removeStopword ["this";"is";"the"]
Others have mentioned the power of pattern matching in this case. In practice, you usually have a set of stopwords you want to remove. And the when guard allows us to pattern match quite naturally:
let rec removeStopwords (stopwords: Set<string>) = function
| x::xs when Set.contains x stopwords -> removeStopwords stopwords xs
| x::xs -> x::(removeStopwords stopwords xs)
| [] -> []
The problem with this function and #John's answer is that they are not tail-recursive. They run out of stack on a long list consisting of a few stopwords. It's a good idea to use high-order functions in List module which are tail-recursive:
let removeStopwords (stopwords: Set<string>) xs =
xs |> List.filter (stopwords.Contains >> not)
Related
I am trying to obtain a specific value from one list with a multiple recursion so I have :
type PowerSystem =
| System of string * int
| Junction of string * List<PowerSystem>
let Starship =
Junction("Core",
[
Junction("Users",
[
System("Main Computer",-10);
System("Library Computer",-10);
Junction("Defence",)]
let rec JunctionPath (pSystem:PowerSystem) =
match pSystem with
| Junction(name,aList) -> SplitList2 aList
| System(name,aNumber) -> [name]
and SplitList2 list =
match list with
| [] -> printfn "%A" []
| head::tail -> printfn "%A" List.filter (fun e->e="Port Phasers" (JunctionPath head)#(SplitList2 tail))
JunctionPath Starship
I get error FS0001: The type ''a -> string list' does not match the type 'unit'
I want to get the name of junctions when the system is called Main Computer but I can't call other functions. I tryed in different ways to get those values but I can't found the way. Thanks in advance
SplitList2 only has the side effect of printfn hence returns unit ().
In JunctionPath the first branch returns a list of string - [name] - and the second a unit due to calling SplitList2. This is not allowed as both (in general all) pattern match branches should return the same type. This is why you get your error "error FS0001: The type ''a -> string list' does not match the type 'unit'"
(It would be clearer if you, in future, note the line references in the error as that points to the problematic line).
Now in answer to your last point:
I want to get the name of junctions when the system is called Main
Computer but I can't call other functions. I tryed in different ways
to get those values but I can't found the way.
this does not make sense since what is "Port Phasers"? Anyway, without testing, I have modified SplitList2 to return a list on either branch. Then we pipe the result of JunctionPath into a printfn. However the logic of the line List.filter (fun e->e="Port Phasers" (JunctionPath head)#(SplitList2 tail)) still does not make sense, so I updated it as I think you meant it (although you should have had another error for this?). (This is not tail recursive and can be improved but one step at a time)
type PowerSystem =
| System of string * int
| Junction of string * List<PowerSystem>
let Starship =
Junction("Core",
[
Junction("Users",
[
System("Main Computer",-10);
System("Library Computer",-10);
Junction("Defence",)]
let rec JunctionPath (pSystem:PowerSystem) =
match pSystem with
| Junction(name,aList) -> SplitList2 aList
| System(name,aNumber) -> [name]
and SplitList2 list =
match list with
| [] -> []
| head::tail -> List.filter (fun e->e="Port Phasers") (JunctionPath head)#(SplitList2 tail))
JunctionPath Starship |> printfn "%A%
Is there anyway to contruct a list in reverse order without having to reverse it
Here is an example, I read all lines from stdin
#!/usr/bin/env dotnet fsi
open System
let rec readLines1 () =
let rec helper acc =
match Console.ReadLine() with
| null -> acc
| line ->
helper (line :: acc)
helper [] |> List.rev
readLines1 () |> List.iter (printfn "%s")
Before return from readLines1 I have to List.rev it so that is in right order. Since the result is a slightly linked list it will have to read all trough it and create the reversed version. Is there any way of creating the list in right order?
You can use a sequence instead of accumulating the lines in a list:
open System
let readLines1 () =
let rec helper () =
seq {
match Console.ReadLine() with
| null -> ()
| line ->
yield line
yield! helper ()
}
helper () |> Seq.toList
readLines1 () |> List.iter (printfn "%s")
You cannot create list in reverse order, because that would require mutation. If you read inputs one by one, and want to turn them into a list immediately, the only thing you can do is to create new list, linking to the previous one.
In practice, reversing the list is perfectly fine and that's probably the best way of solving this.
Out of curiosity, you could try defininig a mutable list that has the same structure as immutable F# list:
open System
type MutableList<'T> =
{ mutable List : MutableListBody<'T> }
and MutableListBody<'T> =
| Empty
| Cons of 'T * MutableList<'T>
Now you can implement your function by mutating the list:
let rec readLines () =
let res = { List = Empty }
let rec helper acc =
match Console.ReadLine() with
| null -> res
| line ->
let next = { List = Empty }
acc.List <- Cons(line, next)
helper next
helper res
This may be educational, but it's not very useful and, if you really wanted mutation in F#, you should probably use ResizeArray.
Yet another trick is to work with functions that take the tail of the list:
let rec readLines () =
let rec helper acc =
match Console.ReadLine() with
| null -> acc []
| line -> helper (fun tail -> acc (line :: tail))
helper id
In the line case, this returns a function that takes tail adds line before the tail and then calls whatever function was constructed before to add more things to the front.
This actually creates the list in the right order, but it's probably less efficient than creating a list and reversing it. It may look nice, but you are allocating a new function for each iteration, which is not better than allocating an extra copy of the list. (But it is a nice trick, nevertheless!)
Alternative solution without implementing recursive functions
let lines =
Seq.initInfinite (fun _ -> Console.ReadLine())
|> Seq.takeWhile (not << isNull)
|> Seq.toList
I created a nested Discriminated Union (DU) as follows:
type OptimizationPeriod = | All
| Long
| Short
type OptimizationCriterion = | SharpeRatio of OptimizationPeriod
| InformationRatio of OptimizationPeriod
| CalmarRatio of OptimizationPeriod
and also a non-nested DU:
type Parallelism = Sequential | PSeq
I have a JSON configuration file with strings that define the DU cases. The following function manages to identify the case of the non-nested Parallelism DU :
let stringToDUCase<'t> (name: string) : 't =
let dUCase =
Reflection.FSharpType.GetUnionCases( typeof<'t> )
|> Seq.tryFind (fun uc -> uc.Name = name)
|> Option.map (fun uc -> Reflection.FSharpValue.MakeUnion( uc, [||] ) :?> 't)
match dUCase with
| Some x -> x
| _ -> let msg = sprintf "config.json - %s is not a case in DU %A" name typeof<'t>
failwith msg
Note: I certainly copied it from somewhere as the function is a bit over my head, apologies to the author for not remembering where it came from.
Unfortunately this function fails to identify the case for the nested DU:
stringToDUCase<OptimizationCriterion> config.Trading.Criterion
System.Exception: config.json - SharpeRatio All is not a case in DU FractalTypes.OptimizationCriterion
Two questions:
1) I was able to write a function that deals specifically with the OptimizationCriterion DU and is able to identify the case. Is there a generic function along the lines of stringToDUCase that could do the same?
2) Would it be better to use a tuple of type OptimizationCriterion*OptimizationPeriod instead of a nested DU? (I probably would have to call stringToDUCase twice, but that is not a problem)
An "empty" DU case like All is just a value, but a "non-empty" DU case like SharpeRatio is actually a function that takes one value and returns the type. In this case, SharpeRatio has the type OptimizationPeriod -> OptimizationCriterion.
Your existing stringToDUCase function always passes an empty array into MakeUnion (implying an empty DU case). So here's a modified version of the function that works for any DU case:
let stringToParamDUCase<'t> (name: string) =
Reflection.FSharpType.GetUnionCases(typeof<'t>)
|> Seq.tryFind (fun uc -> uc.Name = name)
|> Option.map (fun uc ->
fun (parameters:obj []) -> Reflection.FSharpValue.MakeUnion(uc, parameters) :?> 't)
|> Option.defaultWith (fun () ->
failwith (sprintf "config.json - %s is not a case in DU %A" name typeof<'t>))
Note that it returns a function of obj [] -> 't. I've also simplified the error handling a little bit.
This is how you might use it:
let myOptimizationPeriod = stringToParamDUCase<OptimizationPeriod> "All" [||]
let f = stringToParamDUCase<OptimizationCriterion> "SharpeRatio"
let myOptimizationCriterion = f [|All|]
I think the existing answer should answer your question directly. However, I think it is worth making two additional points. First, it might be easier if you represented your OptimizationCriterion as a record, because all your DU cases contain the same value:
type OptimizationPeriod =
| All | Long | Short
type OptimizationRatio =
| SharpeRatio | InformationRatio | CalmanRatio
type OptimizationCriterion =
{ Ratio : OptimizationRatio
Period : OptimizationPeriod }
This happens to solve your problem too, because now you only need DUs without parameters, but I think it is also better design, because you avoid duplicating the second parameter.
Second, I don't think you really need to go with a fancy custom reflection-based function for deserialization. If you want to store your data in a JSON, you should either use standard library (Newtonsoft.JSON or Chiron will do just fine), or you can write this directly using something like JsonValue from F# Data, but using custom reflection code is a quick way leading to unmaintainable code.
Suppose I have a DU like so:
type DU = Number of int | Word of string
And suppose I create a list of them:
[Number(1); Word("abc"); Number(2)]
How can I write a function that would return true for a list of DUs where all the elements are the same case. For the above list it should return false.
The general approach I'd use here would be to map the union values into tags identifying the cases, and then check if the resulting set of tags has at most one element.
let allTheSameCase (tagger: 'a -> int) (coll: #seq<'a>) =
let cases =
coll
|> Seq.map tagger
|> Set.ofSeq
Set.count cases <= 1
For the tagger function, you can assign the tags by hand:
allTheSameCase (function Number _ -> 0 | Word _ -> 1) lst
or use reflection (note that you might need to set binding flags as necessary):
open Microsoft.FSharp.Reflection
let reflectionTagger (case: obj) =
let typ = case.GetType()
if FSharpType.IsUnion(typ)
then
let info, _ = FSharpValue.GetUnionFields(case, typ)
info.Tag
else -1 // or fail, depending what makes sense in the context.
In case you wanted to check that the elements of a list are of a specific union case, it's straightforward to provide a predicate function.
let isNumbers = List.forall (function Number _ -> true | _ -> false)
If you do not care which union case, as long as they are all the same, you need to spell them all out explicitly. Barring reflection magic to get a property not exposed inside F#, you also need to assign some value to each case. To avoid having to think up arbitrary values, we can employ an active pattern which maps to a different DU behind the scenes.
let (|IsNumber|IsWord|) = function
| Number _ -> IsNumber
| Word _ -> IsWord
let isSameCase src =
src |> Seq.groupBy (|IsNumber|IsWord|) |> Seq.length <= 1
I had the exact same use case recently and the solution can be done much simpler than complicated reflections or explicit pattern matching, GetType does all the magic:
let AreAllElementsOfTheSameType seq = // seq<'a> -> bool
if Seq.isEmpty seq then true else
let t = (Seq.head seq).GetType ()
seq |> Seq.forall (fun e -> (e.GetType ()) = t)
I want to refine the raw text by using regular expression, given a list of (patten,replacement) tuple.
I tried to use the patten matching on the list element but failed, the error showed that "This expression was expected to have type string * string list but here has type 'a list".
How can I fix this problem? Thanks a lot.
Codes are as follows:
let rec refine (raw:string) (rules:string*string list) =
match rules with
| (pattern,replacement) :: rest ->
refine <| Regex.Replace(raw,pattern,replacement) rest
| [] -> raw
The problem is that a string * string list is a pair consisting of a string and a list of strings, whereas you want a (string * string) list:
let rec refine (raw:string) (rules:(string*string) list) =
match rules with
| (pattern,replacement) :: rest ->
refine (Regex.Replace(raw,pattern,replacement)) rest
| [] -> raw
Alternatively, the only reason you need that particular annotation is because Regex.Replace is overloaded. This is why your other solution works, but there are other (more minimal) places you can put an annotation that will work:
let rec refine (raw:string) rules =
match rules with
| (pattern,replacement:string) :: rest ->
refine (Regex.Replace(raw,pattern,replacement)) rest
| [] -> raw
Finally it works when I try this:
let rec refine (raw:string) rules =
match rules with
| rule :: rest ->
//get tuple values beyond the patten matching
let (pattern:string,replacement:string) = rule
refine (Regex.Replace(raw,pattern,replacement)) rest
| [] -> raw