This question already has answers here:
How to have two methods calling each other?
(4 answers)
Closed 8 years ago.
I have two functions :
let fn2 =
if "something happend" then
fn1
let rec fn1 =
if "something" then
fn2
This is just an example, what I am trying to do. Is there any Idea how to do it?
or should I just send the 2. function to the 1. function as parameter?
You need to use let rec ... and ...:
let rec fn1 x =
if x = "something" then
fn2 x
and fn2 x =
if x = "something else" then
fn1 x
You can also nest wrap your functions and create two higher-order-functions that take a function as an argument and apply it.
This could than be sth. like:
let fn2 fn =
if "something happend" then
fn fn2
let rec fn1 fn =
if "something" then
fn fn1
You can call than call your function like this:
let result = fn1 fn2
If you want your function to be more explicit your can write it for example like:
let rec fn2 (fn:unit->unit) : unit =
if "something happend" then
fn fn2
let rec fn1 (fn:unit->unit) : unit =
if "something" then
fn fn1
But I think kvb's answer is they better way to go because it is more standard-conform and readable.
Related
For the 1st snippet below my f# noob heart felt that the 2nd snippet is better (no fun z ->):
let json = ...
|> Seq.map(fun z -> new ...)
|> fun z -> JsonSerializer.Serialize(z, options = new JsonSerializerOptions( WriteIndented = true))
let serialise z = JsonSerializer.Serialize(z, options = new JsonSerializerOptions( WriteIndented = true))
let json = ...
|> Seq.map(fun z -> new ...)
|> serialise
If I wished to pass parameters then this feels better:
let serialise options z = JsonSerializer.Serialize(z, options = options)
let json = ...
|> Seq.map(fun z -> new ...)
|> serialise (new JsonSerializerOptions( WriteIndented = true ))
When learning the language I'd like to do things in the spirit of it, and hence my question:
Is any of this forms "more F#"?
This is an opinion question, so there's no right answer. Personally, I almost never pipe directly into a lambda (|> fun z ->), and wouldn't bother writing a curried serialise function unless it'll be called more than once. So here's how I would write this:
let json =
let things =
... |> Seq.map (fun z -> new ...)
JsonSerializer.Serialize(
things,
new JsonSerializerOptions(WriteIndented = true))
Note that things is scoped to the json block, so it doesn't pollute the rest of the code.
Your third option is generally my preferred way of doing things. Ultimately, I focus on readability and refactorability and let that guide my approach.
I'm using quite a lot this piece of code:
let inline (||>) (a: 'a option) (b: 'a -> unit) = if a.IsSome then b a.Value
so I can do things like
myData ||> DoSomethingWithIt
without having to test if myData is Some or None since there are many functions that don't generally need to test for an option. This avoid to put the test in the function itself.
I would like to extend this to methods of a type where I could do like C#'s:
myData?.DoSomethingWithIt
essentially replacing:
if myData.IsSome then myData.Value.DoSomethingWithIt
with some syntactic sugar.
but I have no idea how I could do the operator so that it allows to get access to the type's method in the expression. Is that possible in F#?
I'm also open to learn about why it could be a bad idea if it is :)
Depending on your return type of DoSomethingWithIt the F# library offers a few standard functions for working with Options that can be turned into operators.
let x = Some 1
let aPrinter a = printfn "%i" a
let add1 a = a + 1
let (|?>) opt f = Option.iter f opt
let (|??>) opt f = Option.map f opt
x |?> aPrinter
let y = x |??> add1
You can also consider redefining your DoSomethingWithIt to work with an option by partial application.
let DoSomethingWithIt' = Option.iter DoSomethingWithIt
let something' = Option.iter (fun (b:B) -> b.DoSomethingWithIt()) //For instance methods
That may end up being a lot of work depending how many functions you are dealing with.
Ultimately you shouldn't try to hide the fact you are working with Options. By making something an Option you are telling the compiler that you aren't sure whether it exists or not. It is trying to help you by forcing you to deal with the None case. If there are lots of cases in your code where you know your Option is Some then there's probably a larger architectural issue in your code and you should try to lift all your Option<'T> to just T prior to doing work with them. e.g.:
let lift xs =
[
for x in xs do
match x with
| Some x -> yield x
| None -> ()
]
Have a look at Option.iter. It has the same signature as your operator.
There is no analogical syntax for such constructions but F# have alternatives.
The easiest way is to use FSharpx.Extras library and FSharpx.Option.maybe computation expression which will allow you to use Option related operations.
open FSharpx.Option
let a = Some 1
let b = maybe {
let! v = a
return v + 3
} // b is (Some 4)
let c : int option = None
let d = maybe {
let! v = c
return v + 3 // this line won't be reached
} // d is None
I believe that the ?. operator in c# is a syntactic sugar that hides the if statement checking for null before invoking a member of the type. Even if you could make it work the way you plan, I feel that it would go against the FP principles and could cause more problems down the line.
The Option module contains probably most of what you need already. The iter function allows to call a function on the value of the Option if that value is present (Some).
If you have situation that your input parametes can be nulls, but not options, you can use the Option.ofObj function that will convert the parameter to an Option with Some if the parameter is not null, else None.
So assuming that your function DoSomethingWithit accepts a string and returns unit:
let DoSomethingWithIt = //(string -> unit)
printf "%s; "
You can use this more verbose syntax to (for example) iterate over nullable values in your list:
let lst = [ "data"; "data 2"; null; "data3" ]
lst
|> List.iter (fun v -> v |> Option.ofObj |> Option.iter DoSomethingWithIt)
Alternatively you can compose the Optioni.ofObj and Option.iter DoSomethingWithIt functions and do something like
let SafeDoSomethingWithIt = //(string -> unit)
Option.ofObj >> Option.iter DoSomethingWithIt
This gives you safe invocation:
let lst2 = [ "data"; "data 2"; null; "data3" ]
lst2
|> List.iter SafeDoSomethingWithIt
You can generalize the combination of the functions returning unit (but not only)
let makeSafe fn =
Option.ofObj >> Option.iter fn
Then you can create a series of safe functions:
let SafeDoSomethingWithIt = makeSafe DoSomethingWithIt
let safePrint = makeSafe (printf "%s; ")
//...etc
Then this still works:
lst2
|> List.iter SafeDoSomethingWithIt
lst2
|> List.iter safePrint
You can also write a wrapper for functions returning values using Option.bind function.
let makeSafeReturn fn = //(string -> string option)
Option.ofObj >> Option.bind fn
I have a function processing a DataTable looking for any row that has a column with a certain value. It looks like this:
let exists =
let mutable e = false
for row in dt.Rows do
if row.["Status"] :?> bool = false
then e <- true
e
I'm wondering if there is a way to do this in a single expression. For example, Python has the "any" function which would do it something like this:
exists = any(row for row in dt.Rows if not row["Status"])
Can I write a similar one-liner in F# for my exists function?
You can use the Seq.exists function, which takes a predicate and returns true if the predicate holds for at least one element of the sequence.
let xs = [1;2;3]
let contains2 = xs |> Seq.exists (fun x -> x = 2)
But in your specific case, it won't work right away, because DataTable.Rows is of type DataRowCollection, which only implements IEnumerable, but not IEnumerable<T>, and so it won't be considered a "sequence" in F# sense, which means that Seq.* functions won't work on it. To make them work, you have to first cast the sequence to the correct type with Seq.cast:
let exists =
dt.Rows |>
Seq.cast<DataRow> |>
Seq.exists (fun r -> not (r.["Status"] :?> bool) )
Something like this (untested):
dt.Rows |> Seq.exists (fun row -> not (row.["Status"] :?> bool))
https://msdn.microsoft.com/visualfsharpdocs/conceptual/seq.exists%5b%27t%5d-function-%5bfsharp%5d
This question already has answers here:
Generic type annotation in F#
(2 answers)
Closed 7 years ago.
Let's say we have the following function (body isn't very important):
let writelogf greeting x =
Printf.printf "%A" greeting
Printf.printf "%A" x
The type of this function is 'a -> 'b -> unit which is what I want.
Now I define a partially applied function:
let logf x = writelogf "Hello!" x
The type of this function is 'a -> unit which is what I expect. I'm able to use it with arguments of any type:
logf "Test"
logf 1
But if I try to simplify the declaration and repeat the calls:
let logf2 = writelogf "Hello!"
logf2 "Test"
logf2 1
it won't compile anymore, because logf2 is not generalized, it has type string -> unit (infered from first usage).
Why is that? If I have a function with 5 parameters and I need to partially apply one, do I have to repeat the other 4?
In the case where you have written:
let logf2 = writelogf "Hello!"
You are effectively binding a value, the type of which is generic. If you change your definition into a function, e.g. by taking the argument explicitly, or an argument of unit type, you can resolve the issue.
let logf x = writelogf "Hello!" x
let logf2() = writelogf "Hello!"
If you have a function with 5 parameters and you partially apply one, again you will need to take at least one argument explicitly but you do not need to repeat the other 3.
let test5 a b c d e =
printfn "%A" (a, b, c, d, e)
let testApplyOne x = test5 "Hello!" x
I got the following error:
Error 2 Value restriction. The value 'gbmLikelihood' has been inferred to have generic type val gbmLikelihood : (float -> '_a -> float [] -> float) when '_a :> seq<float> Either make the arguments to 'gbmLikelihood' explicit or, if you do not intend for it to be generic, add a type annotation.
and this type is exactly what I want. What do I have to do to make it work, and why doesn't it just work without intervention?
EDIT:
The error comes from this file (its short, so I paste the whole lot):
module Likelihood
open System
let likelihood getDrift getVol dt data parameters =
let m = getDrift data parameters
let s = getVol data parameters
let N = float (Seq.length data)
let sqrt_dt = Math.Sqrt dt
let constant = -0.5*Math.Log(2.0*Math.PI*dt)*N
let normalizedResidue observation = (observation - (m - 0.5*s*s)*dt)/(s*sqrt_dt)
let residueSquared observation =
let r = normalizedResidue observation in r*r
let logStdDev = Math.Log s
constant - logStdDev*N - 0.5* (data |> Seq.sumBy residueSquared)
let gbmLikelihood = likelihood (fun data p -> Array.get p 0) (fun datac p -> Array.get p 1)
This error can happen when you declare a value that has a generic type. See for example this past SO question. In your case, the type suggests that you are trying to define a function, but the compiler does not see it as a syntactic function. This can happen if you perform some effects and then return function using the lambda syntax:
let wrong =
printfn "test"
(fun x -> x)
To avoid the problem, you need to write the function using the function syntax:
printfn "test"
let wrong x = x
EDIT: In your concrete example, the function gbmLikelihood is created as a result of a partial function application. To make it compile, you need to turn it into an explicit function:
let gbmLikelihood parameters =
likelihood (fun data p -> Array.get p 0) (fun datac p -> Array.get p 1) parameters
For more information why this is the case & how it works, see also this great article on value restriction in F#.
Instead of making the parameters of gbmLikelihood explicit you might also just add a generic type annotation to the function:
let gbmLikelihood<'a> =
likelihood (fun data p -> Array.get p 0) (fun datac p -> Array.get p 1)