I have a function in F# , like:
let MyFunction x =
let workingVariable1 = x + 1
let workingVariable2 = workingVariable1 + 1
let y = workingVariable2 + 1
y
Basically, MyFunction takes an input x and returns y. However, in the process of calculation, there are a few working variables (intermediate variables), and due to the nature of my work (civil engineering), I need to report all intermediate results. How should I store all working variables of the function ?
I'm not exactly sure what kind of "report" your are expecting. Is this a log of intermediate values ? How long time this log should be kept ? etc. etc This is my attempt from what I understand. It is not ideal solution because it allows to report values of intermediate steps but without knowing exactly which expression has generated the intermediate value (I think that you would like to know that a value n was an output of workingVariable1 = x + 1 expression).
So my solution is based on Computation Expressions. Computation expression are a kind of F# "monads".
First you need to define a computation expression :
type LoggingBuilder() =
let log p = printfn "intermediate result %A" p
member this.Bind(x, f) =
log x
f x
member this.Return(x) =
x
Next we create an instance of computation expression builder :
let logIntermediate = new LoggingBuilder()
Now you can rewrite your original function like this:
let loggedWorkflow x =
logIntermediate
{
let! workingVariable1 = x + 1
let! workingVariable2 = workingVariable1 + 1
let! y = workingVariable2 + 1
return y,workingVariable1,workingVariable2
}
If you run loggedWorkflow function passing in 10 you get this result :
> loggedWorkflow 10;;
intermediate result 11
intermediate result 12
intermediate result 13
val it : int * int * int = (13, 11, 12)
As I said your intermediate values are logged, however you're not sure which line of code is responsible for.
We could however enchance a little bit to get the FullName of the type with a corresponding line of code. We have to change a little our computation expression builder :
member this.Bind(x, f) =
log x (f.GetType().FullName)
f x
and a log function to :
let log p f = printfn "intermediate result %A %A" p f
If you run again loggedWorkflow function passing in 10 you get this result (this is from my script run in FSI) :
intermediate result 11 "FSI_0003+loggedWorkflow#34"
intermediate result 12 "FSI_0003+loggedWorkflow#35-1"
intermediate result 13 "FSI_0003+loggedWorkflow#36-2"
This is a hack but we get some extra information about where the expressions like workingVariable1 = x + 1 were definied (in my case it is "FSI_") and on which line of code (#34, #35-1). If your code changes and this is very likely to happen, your intermediate result if logged for a long time will be false. Note that I have not tested it outside of FSI and don't know if lines of code are included in every case.
I'm not sure if we can get an expression name (like workingVariable1 = x + 1) to log from computation expression. I think it's not possible.
Note: Instead of log function you coud define some other function that persist this intermediate steps in a durable storage or whatever.
UPDATE
I've tried to came up with a different solution and it is not very easy. However I might have hit a compromise. Let me explain. You can't get a name of value is bound to inside a computation expression. So we are not able to log for example for expression workingVariable1 = x + 1 that "'workingVariable1' result is 2". Let say we pass into our computation expression an extra name of intermediate result like that :
let loggedWorkflow x =
logIntermediate
{
let! workingVariable1 = "wk1" ## x + 1
let! workingVariable2 = "wk2" ## workingVariable1 + 1
let! y = "y" ## workingVariable2 + 1
return y,workingVariable1,workingVariable2
}
As you can see before ## sign we give the name of the intermediate result so let! workingVariable1 = "wk1" ## x + 1 line will be logged as "wk1".
We need then an extra type which would store a name and a value of the expression :
type NamedExpression<'T> = {Value:'T ; Name: string}
Then we have to redefine an infix operator ## we use une computation expression :
let (##) name v = {Value = v; Name = name}
This operator just takes left and right part of the expression and wraps it within NamedExpression<'T> type.
We're not done yet. We have to modify the Bind part of our computation expression builder :
member this.Bind(x, f) =
let {Name = n; Value = v} = x
log v n
f v
First we deconstruct the NamedExpression<'T> value into name and wraped value. We log it and apply the function f to the unwrapped value v. Log function looks like that :
let log p n = printfn "'%s' has intermediate result of : %A" n p
Now when you run the workflow loggedWorkflow 10;; you get the following result :
'wk1' has intermediate result of : 11
'wk2' has intermediate result of : 12
'y' has intermediate result of : 13
Maybe there are better way to do that, something with compiler services or so, but this is the best attempt I could do so far.
If I understand you correctly, then there are several options:
let MyFunction1 x =
let workingVariable1 = x + 1
let workingVariable2 = workingVariable1 + 1
let y = workingVariable2 + 1
y,workingVariable1,workingVariable2
MyFunction1 2 |> printfn "%A"
type OneType()=
member val Y = 0 with get,set
member val WV1 = 0 with get,set
member val WV2 = 0 with get,set
override this.ToString() =
sprintf "Y: %d; WV1: %d; WV2: %d\n" this.Y this.WV1 this.WV2
let MyFunction2 x =
let workingVariable1 = x + 1
let workingVariable2 = workingVariable1 + 1
let y = workingVariable2 + 1
new OneType(Y=y,WV1=workingVariable1,WV2=workingVariable2)
MyFunction2 2 |> printfn "%A"
Out:
(5, 3, 4)
Y: 5; WV1: 3; WV2: 4
http://ideone.com/eYNwYm
In the first function uses the tuple:
https://msdn.microsoft.com/en-us/library/dd233200.aspx
The second native data type.
https://msdn.microsoft.com/en-us/library/dd233205.aspx
It's not very "functional" way, but you can use mutable variable to store intermediate results:
let mutable workingVariable1 = 0
let mutable workingVariable2 = 0
let MyFunction x =
workingVariable1 <- x + 1
workingVariable2 <- workingVariable1 + 1
let y = workingVariable2 + 1
y
Related
I have to write a function sum that takes as first argument a value n. The second argument is a function f so that sum calculates the Gaussian sum.
In a second step, I have to implement thesum_gauss (int->int) using sum and a lambda expression.
This is my idea for the function sum:
let rec sum (n:int) (f:int->int) : int =
if n < 1 then 0
else sum (n-1) f + f n
And this is sum_gauss which throws an error:
let sum_gauss = sum ((i:int) -> fun (i:int) : int -> i)
The error is:
Line 1, characters 30-32:
Error: Syntax error: ')' expected
Line 1, characters 22-23:
This '(' might be unmatched
I don't understand why this error is raised because every left bracket is matched by a right bracket.
Rewriting with type inference cleaning things up:
let rec sum n f =
if n < 1 then 0
else sum (n-1) f + f n
If you wish to add all number from 1 to n. you need to pass the number and the function to sum_gauss as separate arguments.
let sum_gauss n = sum n (fun x -> x)
Of course, fun x -> x is really just Fun.id.
let sum_gauss n = sum n Fun.id
If you feel like being extra clever and you're already using the Fun module you can use Fun.flip to pass Fun.id as the second argument of sum and elide n from the definition entirely. The fact that sum is not polymorphic avoids weak typing issues with partial application.
let gauss_sum = Fun.(flip sum id)
I am working on the following exercise:
Define a function libDiv which computes the list of natural divisors of some positive integer.
First define libDivInf, such that libDivInf n i is the list of divisors of n which are lesser than or equal to i
libDivInf : int -> int -> int list
For example:
(liDivInf 20 4) = [4;2;1]
(liDivInf 7 5) = [1]
(liDivInf 4 4) = [4;2;1]
Here's is my attempt:
let liDivInf : int -> int -> int list = function
(n,i) -> if i = 0 then [] (*ERROR LINE*)
else
if (n mod i) = 0 (* if n is dividable by i *)
then
i::liDivInf n(i-1)
else
liDivInf n(i-1);;
let liDiv : int -> int list = function
n -> liDivInf n n;;
I get:
ERROR: this pattern matches values of type 'a * 'b ,but a pattern
was expected which matches values of type int
What does this error mean? How can I fix it?
You've stated that the signature of liDivInf needs to be int -> int -> int list. This is a function which takes two curried arguments and returns a list, but then bound that to a function which accepts a single tuple with two ints. And then you've recursively called it in the curried fashion. This is leading to your type error.
The function keyword can only introduce a function which takes a single argument. It is primarily useful when you need to pattern-match on that single argument. The fun keyboard can have multiple arguments specified, but does not allow for pattern-matching the same way.
It is possible to write a function without using either.
let foo = function x -> x + 1
Can just be:
let foo x = x + 1
Similarly:
let foo = function x -> function y -> x + y
Can be written:
let foo x y = x + y
You've also defined a recursive function, but not included the rec keyword. It seems you're looking for something much more like the following slightly modified version of your attempt.
let rec liDivInf n i =
if i = 0 then
[]
else if (n mod i) = 0 then
i::liDivInf n (i-1)
else
liDivInf n (i-1)
I am new to this, and I am looking for help. I currently am stuck in a program I'm trying to complete. Here it is:
def printStock(stockList, stockPrice, p):
for i in range(len(stockPrice)):
if stockPrice[i] > p:
p = stockList[i]
print("The stocks with a higher value are:", p)
def searchStock(stockList, stockPrice, s):
for i in range(len(stockList)):
if s == stockList[i]:
s = stockPrice[i]
elif s != stockList[i]:
s = -1
return s
def mainFun():
stockList= []
stockPrice = []
l = 1
while l > 0:
stocks = str(input("Enter the name of the stock:"))
stockList += [stocks]
if stocks == "done"or stocks == 'done':
l = l * -1
stockList.remove("done")
else:
price = int(input("Enter the price of the stock:"))
stockPrice += [price]
l = l + 1
print(stockList)
print(stockPrice)
s = input("Enter the name of the stock you're looking for:")
searchStock(stockList, stockPrice, s)
p = s
printStock(stockList, stockPrice, p)
Every time I run the program to the end, it never returns the variable s for some reason. If i replace return with print, it always prints -1 instead of the stockPrice if its on the list. I also get an error saying "unorderable types int() > str()" regarding line 3. Basically the function printStock takes the three parameters and once the function is done it should print the names of the stocks higher than the value 'p'. The value of 'p' is the same as the value I get after calling searchStock function, but I cant seem to get it to work. Can someone please help me?
s is being returned from the function, but the return value is not being assigned to any variable on the outer scope.
Just replace
searchStock(stockList, stockPrice, s)
with
s=searchStock(stockList, stockPrice, s)
And everything should work as expected
I'm exploring "advanced" uses of OCaml functions and I'm wondering how I can write a function with variable number of arguments.
For example, a function like:
let sum x1,x2,x3,.....,xn = x1+x2,+x3....+xn
With a bit of type hackery, sure:
let sum f = f 0
let arg x acc g = g (acc + x)
let z a = a
And the (ab)usage:
# sum z;;
- : int = 0
# sum (arg 1) z;;
- : int = 1
# sum (arg 1) (arg 2) (arg 3) z;;
- : int = 6
Neat, huh? But don't use this - it's a hack.
For an explanation, see this page (in terms of SML, but the idea is the same).
OCaml is strongly typed, and many techniques used in other (untyped) languages are inapplicable. In my opinion (after 50 years of programming) this is a very good thing, not a problem.
The clearest way to handle a variable number of arguments of the same type is to pass a list:
# let sum l = List.fold_left (+) 0 l;;
val sum : int list -> int = <fun>
# sum [1;2;3;4;5;6];;
- : int = 21
Continuing my F# learning today by attempting to recreate a simple bisection method using recursion, here I am using the MathNet library to inherit from the Beta distribution.
I receive errors on the function 'search' (binary search method) saying the value is not a function and cannot be applied.
//Beta class inheriting from MathNet Beta distribution
//Extends the class by implementing an InverseCDF function
type newBeta(alpha:double, beta:double) =
inherit MathNet.Numerics.Distributions.Beta(alpha, beta)
member this.InverseCDF(p: float) =
let rec search (min: float, max: float, acc: uint32) =
let x = (min + max) / 2.0
let error = 0.001
let maxiters : uint32 = 1000u
let cdf = this.CumulativeDistribution(x)
match cdf, (Math.Abs(cdf - p) < error || acc > maxiters) with //while statement
| _ , true -> cdf //auto match cdf and if while statement evaluates true then break and return cdf result
| p , _ -> cdf //if exactly matches p then break and return cdf result
| p , false when p > cdf -> search (min) (x) (acc + 1) //if p > cdf then set max = x and increment then call func with new params
| p , false when p < cdf -> search (x) (max) (acc + 1) //if p < cdf then set min = x and increment then call func with new params
search (0.0) (1.0) (0) //Call the bisection method with initial parameters
Can anyone help? Also obviously any input on how to make this more 'functional' would be cool. Havn't been able to run this yet to test due to the error though. My first 2 match patterns look suspect given I'm trying to return the current value of cdf.
As #John said, your fundamental error is that you declared the function in the tuple form but used it in the curried form.
I notice that you pattern-matched cdf with p. The new value p will shadow parameter p of this.InverseCDF; therefore, that parameter isn't available for comparison anymore. You actually compared cdf with cdf itself and two when guards are always false, which you do not want at all.
A few corrections:
Remove cdf from pattern matching since you only want to compare its value with p, not match with specific literals.
Move two when guards up. The last pattern shouldn't be a when guard; the compiler will complain about incomplete pattern matching in that case.
Use suffix u for any arithmetic operation on acc (which is of type unint32).
The new search function:
let rec search (min: float) (max: float) (acc: uint32) =
let x = (min + max) / 2.0
let error = 0.001
let maxiters : uint32 = 1000u
let cdf = this.CumulativeDistribution(x)
match abs(cdf - p) < error || acc > maxiters with // while statement
| false when p > cdf -> search min x (acc + 1u) // if p > cdf then set max = x and increment then call func with new params
| false when p < cdf -> search x max (acc + 1u) // if p < cdf then set min = x and increment then call func with new params
| _ -> cdf // if exactly matches p or returns true then break and return cdf result
search 0.0 1.0 0u // call the bisection method with initial parameters
Your definition is in tuple style, not curried style - just change it to
let rec search (min: float) (max: float) (acc: uint32) =
This is because when you call the function you have used the curried style f a b but your definition has the tupled style f (a,b)
Also, your match cases aren't quite correct - the last two cases will never be matched because the second case will grab them - you probably want
match cdf, (Math.Abs(cdf - p) < error || acc > maxiters) with //while statement
| _ , true -> cdf //auto match cdf and if while statement evaluates true then break and return cdf result
| p when p=cdf, _ -> cdf //if exactly matches p then break and return cdf result
| p , false when p > cdf -> search (min) (x) (acc + 1) //if p > cdf then set max = x and increment then call func with new params
| p , false when p < cdf -> search (x) (max) (acc + 1) //if p < cdf then set min = x and increment then call func with new params