If I have a function that hasn't arguments and works on a list, like :
let listToCheck = function
[] -> raise (Failure "No elements")
| hd :: tl -> returnTrueOrFalse _ (*Where "_" should be the list*)
With returnTrueOrFalse defined as :
let returnTrueOrFalse list_ = .... (*returns true or false*)
.
(*some code*)
.
let isTrue = listToCheck [1;2;3] in isTrue
Now, listToCheck is called on a list and hasn't paramenters.
On the other hand returnTrueOrFalse needs of an argument.
Since listToCheck is a function to call on a list, can I pass that list as argument for returnTrueOrFalse using _ inside listToCheck ? If yes, how?
You can reconstruct the list, or alias the pattern, or just don't split into head and tail at all:
let listToCheck = function
| [] -> raise (Failure "No elements")
| hd :: tl -> returnTrueOrFalse (hd::tl)
let listToCheck = function
| [] -> raise (Failure "No elements")
| (hd :: tl) as list -> returnTrueOrFalse list
let listToCheck = function
| [] -> raise (Failure "No elements")
| list -> returnTrueOrFalse list
Your function doesn't really need to do a pattern match at all:
let listToCheck list =
if list = [] then failwith "No elements"
else returnTrueOrFalse list
However you're probably asking a more general question, not about this particular code. For the general case I think the as pattern is probably what you're looking for, as #Bergi suggests.
Related
I have a problem with how nested functions should be implemented in OCaml, i need the output (list) of one function to be the input of another. And both should be recursive. The problem is i've played around with the parameters and they arent feeding properly:
let toComb sentence =
let rec listCleanup sentence =
match sentence with
| [] -> []
| h::t when h = "" -> listCleanup t
| h::t -> h::listCleanup t
in
let rec toString listCleanup sentence =
match listCleanup sentence with
| [] -> ""
| [element] -> element
| h::t -> h ^ " " ^ toString listCleanup sentence
in
toString listCleanup sentence;;
If I use the function and its parameter as a parameter, there's a stack overflow, but if I use just the function without a parameter, I get a mismatch of parameters. What should be the fix here?
To correct your code, here is what would work properly:
let to_comb sentence =
let rec cleanup s = match s with
| [] -> []
| ""::tail -> cleanup tail
| hd::tail -> hd::cleanup tail in
let rec to_string s = match s with
| [] -> ""
| [x] -> x
| hd::tail -> hd ^ " " ^ to_string tail in
to_string (cleanup s)
Note that I only call cleanup once, because you only ever need to clean the whole sequence only once. However, turns out both of these function can be expressed more simply with predefined OCaml function:
let to_comb sentence =
sentence
|> List.filter (fun s -> s <> "")
|> String.concat " "
You could almost read this code out loud to get a description of what it does. It starts with a sentence, filters the empty words in it, then concatenates them with spaces in between.
I would like to work with the following type
type RecordPath<'a,'b> = {
Get: 'a -> 'b
Path:string
}
It's purpose is to define a getter for going from record type 'a to some field within 'a of type 'b. It also gives the path to that field for the json representation of the record.
For example, consider the following fields.
type DateWithoutTimeBecauseWeirdlyDotnetDoesNotHaveThisConcept = {
Year:uint
Month:uint
Day:uint
}
type Person = {
FullName:string
PassportNumber:string
BirthDate:DateWithoutTimeBecauseWeirdlyDotnetDoesNotHaveThisConcept
}
type Team = {
TeamName:string
TeamMembers:Person list
}
An example RecordPath might be
let birthYearPath = {
Get = fun (team:Team) -> team.TeamMembers |> List.map (fun p -> p.BirthDate.Year)
Path = "$.TeamMember[*].BirthDate.Year" //using mariadb format for json path
}
Is there some way of letting a library user create this record without ever actually needing to specify the string explicitly. Ideally there is some strongly typed way of the user specifying the fields involved. Maybe some kind of clever use of reflection?
It just occurred to me that with a language that supports macros, this would be possible. But can it be done in F#?
PS: I notice that I left out the s in "TeamMembers" in the path. This is the kind of thing I want to guard against to make it easier on the user.
As you noted in the comments, F# has a quotation mechanism that lets you do this. You can create those explicitly using <# ... #> notation or implicitly using a somewhat more elengant automatic quoting mechanism. The quotations are farily close representations of the F# code, so converting them to the desired path format is not going to be easy, but I think it can be done.
I tried to get this to work at least for your small example. First, I needed a helper function that does two transformations on the code and turns:
let x = e1 in e2 into e2[x <- e1] (using the notation e2[x <- e1] to mean a subsitution, i.e. expression e2 with all occurences of x replaced by e1)
e1 |> fun x -> e2 into e2[x <- e1]
This is all I needed for your example, but it's likely you'll need a few more cases:
open Microsoft.FSharp.Quotations
let rec simplify dict e =
let e' = simplifyOne dict e
if e' <> e then simplify dict e' else e'
and simplifyOne dict = function
| Patterns.Call(None, op, [e; Patterns.Lambda(v, body)])
when op.Name = "op_PipeRight" ->
simplify (Map.add v e dict) body
| Patterns.Let(v, e, body) -> simplify (Map.add v e dict) body
| ExprShape.ShapeVar(v) when Map.containsKey v dict -> dict.[v]
| ExprShape.ShapeVar(v) -> Expr.Var(v)
| ExprShape.ShapeLambda(v, e) -> Expr.Lambda(v, simplify dict e)
| ExprShape.ShapeCombination(o, es) ->
ExprShape.RebuildShapeCombination(o, List.map (simplify dict) es)
With this pre-processing, I managed to write an extractPath function like this:
let rec extractPath var = function
| Patterns.Call(None, op, [Patterns.Lambda(v, body); inst]) when op.Name = "Map" ->
extractPath var inst + "[*]." + extractPath v.Name body
| Patterns.PropertyGet(Some(Patterns.Var v), p, []) when v.Name = var -> p.Name
| Patterns.PropertyGet(Some e, p, []) -> extractPath var e + "." + p.Name
| e -> failwithf "Unexpected expression: %A" e
This looks for (1) a call to map function, (2) a property access on a variable that represents the data source and (3) a property access where the instance has some more property accesses.
The following now works for your small example (but probably for nothing else!)
type Path =
static member Make([<ReflectedDefinition(true)>] f:Expr<'T -> 'R>) =
match f with
| Patterns.WithValue(f, _, Patterns.Lambda(v, body)) ->
{ Get = f :?> 'T -> 'R
Path = "$." + extractPath v.Name (simplify Map.empty body) }
| _ -> failwith "Unexpected argument"
Path.Make(fun (team:Team) -> team.TeamMembers |> List.map (fun p -> p.BirthDate.Year))
The way I solved this is
let jsonPath userExpr =
let rec innerLoop expr state =
match expr with
|Patterns.Lambda(_, body) ->
innerLoop body state
|Patterns.PropertyGet(Some parent, propInfo, []) ->
sprintf ".%s%s" propInfo.Name state |> innerLoop parent
|Patterns.Call (None, _, expr1::[Patterns.Let (v, expr2, _)]) when v.Name = "mapping"->
let parentPath = innerLoop expr1 "[*]"
let childPath = innerLoop expr2 ""
parentPath + childPath
|ExprShape.ShapeVar x ->
state
|_ ->
failwithf "Unsupported expression: %A" expr
innerLoop userExpr "" |> sprintf "$%s"
type Path =
static member Make([<ReflectedDefinition(true)>] f:Expr<'T -> 'R>) =
match f with
|Patterns.WithValue(f, _, expr) ->
let path = jsonPath expr
{
Get = f :?> 'T -> 'R
Path = path
}
| _ -> failwith "Unexpected argument"
Caveat: I don't know enough about these techniques to tell if Tomas' answer performs better in some edge cases than mine.
I am a new at F# and i try to do this task:
Make a function compare : string list -> string list -> int that takes two string lists and returns: -1, 0 or 1
Please help. I spend a lot of time, and i can not understand how to implement this task.
Given the task I assume what your professor wants to teach you with this exercise. I'll try to give you a starting point without
Confusing you
Presenting a 'done-deal' solution
I assume the goal of this task is to work with recursive functions and pattern matching to element-wise compare their elements. It could looks somewhat like this here
open System
let aList = [ "Apple"; "Banana"; "Coconut" ]
let bList = [ "Apple"; "Banana"; "Coconut" ]
let cList = [ "Apple"; "Zebra" ]
let rec doSomething f (a : string list) (b : string list) =
match (a, b) with
| ([], []) ->
printfn "Both are empty"
| (x::xs, []) ->
printfn "A has elements (we can unpack the first element as x and the rest as xs) and B is empty"
| ([], x::xs) ->
printfn "A is empty and B has elements (we can unpack the first element as x and the rest as xs)"
| (x::xs, y::ys) ->
f x y
printfn "Both A and B have elements. We can unpack them as the first elements x and y and their respective tails xs and ys"
doSomething f xs ys
let isItTheSame (a : string) (b : string) =
if String.Equals(a, b) then
printfn "%s is equals to %s" a b
else
printfn "%s is not equals to %s" a b
doSomething isItTheSame aList bList
doSomething isItTheSame aList cList
The example has three different lists, two of them being equal and one of them being different. The doSomething function takes a function (string -> string -> unit) and two lists of strings.
Within the function you see a pattern match as well as a recursive call of doSomething in the last match block. The signatures aren't exactly what you need and you might want to think about how to change the parametrization for cases where you don't want to stop the recursion (the last match block - if the strings are equal you want to keep on comparing, right?).
Just take the code and try it out in FSI. I'm confident, that you'll find the solution 🙂
In F# many collections are comparable if their element type is:
let s1 = [ "a"; "b" ]
let s2 = [ "foo"; "bar" ]
compare s1 s2 // -5
let f1 = [ (fun () -> 1); fun () -> 2 ]
let f2 = [ (fun () -> 3); fun () -> 42 ]
// compare f1 f2 (* error FS0001: The type '(unit -> int)' does not support the 'comparison' constraint. *)
so
let slcomp (s1 : string list) s2 = compare s1 s2 |> sign
Posting for reference as the original question is answered already.
I am trying to input a list into the function and it send me a list with the first half of the elements taken away using f# with the below recursion but I keep running into a base case problem that I just cant figure out. any thoughts? I am using the second shadow list to count how far I need to go until I am half way into the list (by removing two elements at a time)
let rec dropHalf listToDrop shadowList =
match shadowList with
| [] -> listToDrop
| shadowHead2::shadowHead1::shadowTail -> if shadowTail.Length<=1 then listToDrop else
match listToDrop with
|[] -> listToDrop
|listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail
let rec dropHalf listToDrop shadowList =
match shadowList with
| [] -> listToDrop
| shadowHead2::[] -> listToDrop (* odd number! *)
| shadowHead1::shadowHead2::shadowTail ->
match listToDrop with
| [] -> listToDrop (* should never happen? *)
| listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail
i'm afraid i don't use F#, but it's similar to ocaml, so hopefully the following is close to what you're looking for (maybe the comment format has changed?!). the idea is that when you exhaust the shadow you're done. your code was almost there, but the test for length on the shadow tail made no sense.
i want to emphasize that this isn't anything like anyone would write "in real life", but it sounds like you're battling with some weird requirements.
Because you use the shadow list with the same length as the original list and remove elements from these lists with different rates, it's better to create an auxiliary function:
let dropHalf xs =
let rec dropHalf' ys zs =
match ys, zs with
| _::_::ys', _::zs' -> dropHalf' ys' zs'
| _, zs' -> zs' (* One half of the shadow list ys *)
dropHalf' xs xs
If you don't care to traverse the list twice, the following solution is simpler:
let rec drop n xs =
match xs, n with
| _ when n < 0 -> failwith "n should be greater or equals to 0"
| [], _ -> []
| _, 0 -> xs
| _::xs', _ -> drop (n-1) xs'
let dropHalf xs =
xs |> drop (List.length xs/2)
and another simple solution needs some extra space but doesn't have to use recursion:
let dropHalf xs =
let xa = Array.ofList xs
xa.[xa.Length/2..] |> List.ofArray
As a general rule of thumb, if you're calling Length on a list, then there is most likely a better way to do what you're doing. Length has to iterate the entire list and is therefore O(n).
let secondHalf list =
let rec half (result : 'a list) = function
| a::b::sx -> half result.Tail sx
// uncomment to remove odd value from second half
// | (a::sx) -> result.Tail
| _ -> result
half list list
Here is a sample does what you described.
open System
open System.Collections.Generic
let items = seq { 1 .. 100 } |> Seq.toList
let getBackOfList ( targetList : int list) =
if (targetList.Length = 0) then
targetList
else
let len = targetList.Length
let halfLen = len / 2
targetList |> Seq.skip halfLen |> Seq.toList
let shortList = items |> getBackOfList
("Len: {0}", shortList.Length) |> Console.WriteLine
let result = Console.ReadLine()
Hope this helps
I am trying to follow this example (from p137 of Rob Pickering's "Foundations of F#" book) but I can't get it to work with the latest F# CTP.
I appear to be missing the definition of 'Value' on the 3rd line where it does
Value.GetInfo(x)
This generates :
error FS0039: The namespace or module 'Value' is not defined.
Can anyone tell me where this is coming from or what the new syntax is if this is now done differently? (be gentle - this is my first play with F#)
Here's the example I am working from:-
#light
open Microsoft.FSharp.Reflection
let printTupleValues x =
match Value.GetInfo(x) with
| TupleValue vals ->
print_string "("
vals
|> List.iteri
(fun i v ->
if i <> List.length vals - 1 then
Printf.printf " %s, " (any_to_string v)
else
print_any v)
print_string " )"
| _ -> print_string "not a tuple"
printTupleValues ("hello world", 1)
The F# reflection library was rewritten for either Beta 1 or the CTP. Here is your code slightly changed to use the new library, and to avoid using the F# PlusPack (print_string is for OCaml compatibility).
open Microsoft.FSharp.Reflection
let printTupleValues x =
if FSharpType.IsTuple( x.GetType() ) then
let s =
FSharpValue.GetTupleFields( x )
|> Array.map (fun a -> a.ToString())
|> Array.reduce (fun a b -> sprintf "%s, %s" a b)
printfn "(%s)" s
else
printfn "not a tuple"
printTupleValues ("hello world", 1)
Or, if you prefer using match to decompose the tuple, then try this using an active pattern. Advantage is you can add support for additional types pretty easily.
open Microsoft.FSharp.Reflection
let (|ParseTuple|_|) = function
| o when FSharpType.IsTuple( o.GetType() ) ->
Some( FSharpValue.GetTupleFields(o) )
| _ -> None
let printTupleValues = function
| ParseTuple vals ->
let s =
vals
|> Array.map (fun a -> a.ToString())
|> Array.reduce (fun a b -> sprintf "%s, %s" a b)
printfn "(%s)" s
| _ ->
printf "not a tuple"
printTupleValues ("hello world", 1)
I don't know whether your function has been renamed or removed in the current F# versions.
You should take a look at FSharp.Reflection in your IDE's object explorer to check that and maybe read this page.