I'm having a lot of trouble with the test_modifier method in lablgtk2. I can test for Shift, but that isn't very useful for my purposes. Whenever I test if control and another key is pressed nothing happens. I've also tried this:
view#event#connect#key_press ~callback:(fun ev ->
let m = GdkEvent.Key.state ev in
let k = GdkEvent.Key.keyval ev in
if (m = [`CONTROL] && k = _F) then
...
It worked for awhile and then it stopped. What is wrong with the above code that it wouldn't do anything? How can I properly test for a Control key press in lablgtk2?
There can be several modifiers at once so comparing to [`CONTROL] is not valid.
let pr fmt = Printf.ksprintf print_endline fmt
let button label packing f =
let b = GButton.button ~label ~packing () in
let _ = b#connect#clicked ~callback:f in
()
let () =
let locale = GtkMain.Main.init () in
let window = GWindow.window ~title:"test" ~border_width:10 () in
let _ = window#connect#destroy ~callback:GMain.quit in
let mainbox = GPack.vbox ~packing:window#add () in
button "quit" mainbox#pack window#destroy;
let _ = window#event#connect#key_press ~callback:begin fun ev ->
let m = GdkEvent.Key.state ev in
let k = GdkEvent.Key.keyval ev in
if (List.mem `CONTROL m && k = GdkKeysyms._F) then pr "WOO HOO";
if (List.mem `CONTROL m && k = GdkKeysyms._f) then pr "woo hoo";
false
end in
window#event#add [`KEY_PRESS];
window#show ();
GMain.main ()
Related
I'm new to OCAML and was playing around with putting a marker on a random 5X5 square. I've written the example program below. "silly_method1" works but notice that it takes an argument. I don't really have argument to pass in for what I want. I'm just asking for a random number to create my robot on a particular square:
let create = {x = ( Random.int 4); y=3; face = North}
However, I get the same location each time. This makes sense to me... sort of. I'm assuming that the way I've set it up, "create" is basically a constant. It's evaluated once and that's it! I've fixed it below in silly_method2 but look how ugly it is!
let silly_method2 _ = (Random.int 10)
Every time I have to call it, I have to pass in an argument even though I'm not really using it.
What is the correct way to do this? There must be some way to have a function that takes no arguments and passes back a random number (or random tuple, etc.)
And possibly related... Is there a way to tell OCaml not to evaluate the function once and save the result but rather recalculate the answer each time?
Thank you for your patience with me!
Dave
let _ = Random.self_init()
let silly_method1 x = x + (Random.int 10)
let silly_method2 _ = (Random.int 10)
let report1 x = (print_newline(); print_string("report1 begin: "); print_int (silly_method1 x); print_string("report1 end"); print_newline(); )
let report2 y = (print_newline(); print_string("report2 begin: "); print_int(silly_method2 y ); print_string("report2 end"); print_newline(); )
let _ = report1 3
let _ = report1 3
let _ = report1 3
let _ = report2 3
let _ = report2 3
let _ = report2 3
The idiomatic way to define a function in OCaml that doesn't take an argument is to have the argument be (), which is a value (the only value) of type unit:
# let f () = Random.int 10;;
val f : unit -> int = <fun>
# f ();;
- : int = 5
# f ();;
- : int = 2
OCaml doesn't save function results for later re-use. If you want this behavior you have to ask for it explicitly using lazy.
I wish to create two functions : the first one generates a new integer and the second one reset the generator
let a = ref 0 in
let f () = a := !a + 1 and
g () = a := 0; ();;
The REPL shows "Error: Syntax error" on the last two semicolons.
The second let also needs to be followed by an in (see the manual), e.g.,
let inc, reset =
let a = ref 0 in
let f () = a := !a + 1; !a
and g () = a := 0
in (f, g);;
But maybe you want something more like this:
let new_counter () =
let a = ref 0 in
let f () = a := !a + 1; !a
and g () = a := 0
in (f, g);;
I have a F# list and I'm taking two elements of that list.
If the list has 10 elements in it :
let rnd = new Random()
let elem1 = list.Item(rnd.Next(0,9))
let elem2 = list.Item(rnd.Next(0,9))
There is a chance elem1 and elem2 are equal.
I have checked some workarounds and most of them work using a do while, but I don't want to implement a function that may never end in F#.
Is there a way to create a restriction in the random function?
First random : 0 <= x <= 9
Second random : 0 <= y <= 9 <> x
A simple solution:
let rnd = new Random()
let ndx1 = rnd.Next(9)
let ndx2 =
let x = rnd.Next(8)
if x < ndx1 then x else x + 1
let elem1, elem2 = list.[ndx1], list.[ndx2]
Another way, using maths and calling the random function once:
let r = Random().Next(9 * 8)
let x = 1 + r + r / 9
let elem1, elem2 = list.[x / 9], list.[x % 9]
which may be generalised to:
let getTwoElements lst =
let c = List.length lst
let x, y = Math.DivRem(Random().Next(c * (c-1)) * (c+1) / c + 1, c)
lst.[x], lst.[y]
A more declarative approach, taking into account your comment about points in the image:
let rnd = System.Random()
/// this will build you a list of 10 pairs of indices where a <> b.
let indices =
Seq.initInfinite (fun _ -> rnd.Next(0,10), rnd.Next(0,10))
|> Seq.filter (fun (a,b) -> a <> b)
|> Seq.take 10
|> List.ofSeq
/// map indices into actual points.
let elems =
let points = list |> Array.ofList
List.map (fun (a, b) -> points.[a], points.[b]) indices
As a side note, do not use random access on lists. They're not made for that and performance of that is poor. Convert them to an array first.
There are lots of way to achieve this. A simple one would be something like this:
open System
open System.Linq
let rnd = new Random()
let elem1 = list.Item(rnd.Next(0,9))
let elem2 = list.Where(fun x->x <> elem1).ElementAt(rnd.Next(0,8))
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
say I have a parameter x and have several lines using x to calculate y, now there are 10 values of x and I need to use each value to calculate a respective y, and I don't wanna change x each time and run my command lines 10 times, is there any syntax in F# which allows me to repeat those command lines I've already wrote so that I only need to execute one time to work out all 10 values of y?
Thanks in advance
EDITED:I pasted my code down below, basically, what I want is geting alphas for different parameter combinations, my parameters are "shreshold", "WeeksBfReport" and "DaysBfExecution". I have 30 sets of parameter combinations, so I don't wanna go change the parameters and run the command for 30 times. Is there any way for not doing this?
let shreshold= 2.0
let ReportDate = "2008/12/15"
let ExeDate = "2009/01/05"
let WeeksBfReport = 1
let DaysBfExecution = 3
let Rf=0.01
let DateIn=ReportDate.ToDateTimeExact("yyyy/MM/dd").AddWeeks(-WeeksBfReport)
let DateOut=ExeDate.ToDateTimeExact("yyyy/MM/dd").AddWorkDays(-DaysBfExecution)
let DateInString=DateIn.ToString("yyyy/MM/dd")
let DateOutString=DateOut.ToString("yyyy/MM/dd")
let mutable FundMV=0.
let FundTicker=csvTable.AsEnumerable().Select(fun (x:DataRow) -> x.Field<string>("Ticker")).ToArray()
for i in 0..csvTable.Rows.Count-1 do
let FundUnitPrice= float(csvTable.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = FundTicker.[i]).First().Field<string>(DateInString))
let FundShares= float(csvTable1.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = FundTicker.[i]).First().Field<string>(DateInString))
FundMV<-FundMV + FundUnitPrice*FundShares
printfn "%e" FundMV
//use TMV to calculate weights of CSI300 constitutes
let mutable csiTMV=0.
let CSITMV : float array = Array.zeroCreate 300
let DictionaryCSI = Dictionary<String,float>()
for i in 0..299 do
let TMV=float(csvTable3.Rows.[i].Field<string>(DateInString))
csiTMV<-csiTMV + TMV
CSITMV.[i] <- TMV
for i in 0..299 do
let Weight=CSITMV.[i]/csiTMV
DictionaryCSI.[csvTable3.Rows.[i].Field<string>("Stock")]<-Weight
let DictionaryOldOut = Dictionary<String,float>()
let array=csvTable2.AsEnumerable().Select(fun (x:DataRow) -> x.Field<string>("Stock")).ToArray()
let OldOutTMV=ResizeArray<float>()
let DictionaryOldOutWeight = Dictionary<string,float>()
let OldOutWeight : float array = Array.zeroCreate (csvTable2.Rows.Count/2)
for i in 0..(csvTable2.Rows.Count/2)-1 do
let Weight=DictionaryCSI.Item(array.[i+(csvTable2.Rows.Count/2)])
DictionaryOldOutWeight.[csvTable2.Rows.[i+csvTable2.Rows.Count/2].Field<string>("Stock")]<-Weight
OldOutWeight.[i]<- Weight
DictionaryOldOut.[csvTable2.Rows.[i+csvTable2.Rows.Count/2].Field<string>("Stock")]<- Weight*FundMV //OldOut Moving Value
OldOutTMV.Add(Weight)
let OldOutTMVarray=OldOutTMV.ToArray() //create an array of OldOut weights and then sum up
let SumOldOutTMV=Array.fold (+) 0. OldOutTMVarray
let mutable NewInTMV=0.
let NewInWeight : float array = Array.zeroCreate (csvTable2.Rows.Count/2)
let DictionaryNewIn = Dictionary<string,float>()
let DictionaryNewInWeight = Dictionary<string,float>()
for i in 0..csvTable3.Rows.Count-300-1 do
let TMV=float(csvTable3.Rows.[i+300].Field<string>(DateInString))
NewInTMV<-NewInTMV + TMV
let Weight=TMV/(csiTMV+NewInTMV-SumOldOutTMV)
NewInWeight.[i]<-Weight
DictionaryNewInWeight.[csvTable3.Rows.[i+300].Field<string>("Stock")]<-Weight
let MovingValue=Weight*FundMV
DictionaryNewIn.[csvTable3.Rows.[i+300].Field<string>("Stock")]<-MovingValue //NewIn Moving Value
let table2array=csvTable2.AsEnumerable().Select(fun (x:DataRow) -> x.Field<string>("Stock")).ToArray()
let NewInturnoverArray : float array = Array.zeroCreate (csvTable2.Rows.Count/2)
for i in 0..(csvTable2.Rows.Count/2)-1 do
let lastday= float(csvTable2.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = table2array.[i]).First().Field<string>(DateInString))
let turnover = csvTable2.Rows.[i].ItemArray.Skip(3)|>Seq.map(fun (x:obj)-> System.Double.Parse(x.ToString()))|>Seq.toArray
let lastdayindex : (int) =
if lastday= 0. then
let lastdayfake=float(csvTable2.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = table2array.[i+2]).First().Field<string>(DateInString))
let turnoverfake = csvTable2.Rows.[i+2].ItemArray.Skip(3)|>Seq.map(fun (x:obj)-> System.Double.Parse(x.ToString()))|>Seq.toArray
Array.findIndex(fun elem -> elem=lastdayfake) turnoverfake
else
let lastdayfake=lastday
let turnoverfake=turnover
Array.findIndex(fun elem -> elem=lastdayfake) turnoverfake
printfn "%A" lastdayindex
let TurnoverNeed : float array = Array.zeroCreate 21
for t in 0..20 do
TurnoverNeed.[t] <- turnover.[lastdayindex - 20 + t]
let zerotwo : float array = Array.zeroCreate TurnoverNeed.Length
if TurnoverNeed=zerotwo then
let ave_daily_turnover = 0.
NewInturnoverArray.[i] <- ave_daily_turnover
else
let ave_daily_turnover = Seq.average(TurnoverNeed|>Seq.filter(fun x-> x > 0.))
NewInturnoverArray.[i] <- ave_daily_turnover
type totalinfo = {Name:String;Shock:float}
let NewIn=ResizeArray<totalinfo>()
for i in 0..(csvTable2.Rows.Count/2)-1 do
let MovingValue=DictionaryNewIn.Item(array.[i])
let Shock=MovingValue/NewInturnoverArray.[i]
let V= {Name=string(array.[i]); Shock=Shock}
NewIn.Add(V)
let NewInShock=NewIn.ToArray()
let OldOutturnoverArray : float array = Array.zeroCreate (csvTable2.Rows.Count/2)
for i in 0..(csvTable2.Rows.Count/2)-1 do
let turnover = csvTable2.Rows.[i+csvTable2.Rows.Count/2].ItemArray.Skip(3)|>Seq.map(fun (x:obj)-> System.Double.Parse(x.ToString()))
let zero : float array = Array.zeroCreate (turnover|>Seq.toArray).Length
if turnover|>Seq.toArray=zero then
let ave_daily_turnover = 0.
OldOutturnoverArray.[i] <- ave_daily_turnover
else
let ave_daily_turnover = Seq.average(turnover|>Seq.filter(fun x-> x > 0.))
OldOutturnoverArray.[i] <- ave_daily_turnover
let OldOut=ResizeArray<totalinfo>()
for i in 0..(csvTable2.Rows.Count/2)-1 do
let MovingValue=DictionaryOldOut.Item(array.[i+csvTable2.Rows.Count/2])
let Shock=MovingValue/OldOutturnoverArray.[i]
let V= {Name=string(array.[i+csvTable2.Rows.Count/2]); Shock=Shock}
OldOut.Add(V)
let OldOutShock=OldOut.ToArray()
let DoIn=NewInShock |> Array.filter (fun t -> t.Shock >= shreshold)
let DoOut=OldOutShock |> Array.filter (fun t -> t.Shock >= shreshold)
let DoInTicker= Array.map (fun e -> e.Name) DoIn
let DoOutTicker= Array.map (fun e -> e.Name) DoOut
let DoInWeight : float array = Array.zeroCreate DoInTicker.Length
for i in 0..DoInTicker.Length-1 do
DoInWeight.[i] <- DictionaryNewInWeight.Item(DoInTicker.[i])
let TotalDoInWeight= Array.fold (+) 0. DoInWeight
let DoInRatioX : float array = Array.zeroCreate DoInTicker.Length
for i in 0..(DoInTicker.Length)-1 do
DoInRatioX.[i] <- DoInWeight.[i]/TotalDoInWeight
let Beta=csvTable2.AsEnumerable().Select(fun (x:DataRow) -> x.Field<string>("Beta")).ToArray()
//let NewInBeta : float array = Array.zeroCreate (csvTable2.Rows.Count/2)
let DictionaryNewInBeta = Dictionary<string,float>()
for i in 0..(csvTable2.Rows.Count/2)-1 do
// NewInBeta.[i] <- float(Beta.[i])
DictionaryNewInBeta.[csvTable3.Rows.[i+300].Field<string>("Stock")]<-float(Beta.[i])
let DoInBeta : float array = Array.zeroCreate DoInTicker.Length
for i in 0..DoInTicker.Length-1 do
DoInBeta.[i] <- DictionaryNewInBeta.Item(DoInTicker.[i])
let mutable PortfolioBeta=0.
for i in 0..(DoInTicker.Length)-1 do
PortfolioBeta <- PortfolioBeta + DoInRatioX.[i] * DoInBeta.[i]
let mutable PortfolioReturn= 0.
for i in 0..DoInTicker.Length-1 do
let PriceIn= float(csvTable4.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = DoInTicker.[i]).First().Field<string>(DateInString))
let PriceOut= float(csvTable4.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = DoInTicker.[i]).First().Field<string>(DateOutString))
PortfolioReturn <- PortfolioReturn + (1./float(DoInTicker.Length))*(PriceOut - PriceIn)/PriceIn
let IndexIn= float(csvTable4.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = "000300.SH").First().Field<string>(DateInString))
let IndexOut= float(csvTable4.AsEnumerable().Where(fun (x:DataRow) -> x.Field<string>(0) = "000300.SH").First().Field<string>(DateOutString))
let MarketReturn= (IndexOut-IndexIn)/IndexIn
let Alpha= PortfolioReturn-Rf-PortfolioBeta*(MarketReturn-Rf)
Like John said, put it all into a function accepting the changing values as parameters. To can use records to allow you to store the parameter combinations in a list, like so.
type ReportParameters = {
shreshold: float;
ReportDate: string;
ExeDate: string;
WeeksBfReport: int;
DaysBfExecution: int;
Rf: float;
}
type Report = {
NewInShock: totalinfo;
IndexIn: float;
// etc
}
let createReport (reportParams:ReportParameters) : Report =
let shreshold = reportParams.shreshold
let ReportDate = reportParams.ReportDate
let ExeDate = reportParams.ExeDate
let WeeksBfReport = reportParams.WeeksBfReport
let DaysBfExecution = reportParams.DaysBfExecution
let Rf = reportParams.Rf
// Your function code HERE
// Remember to move all type definitions out of this scope.
{ // Report data to return.
NewInShock = NewInShock;
IndexIn = IndexIn;
// etc
}
Using the code is as simple as this:
let reportsToBeGenerated = [
{ shreshold = 2.0; ReportDate = "2008/12/15"; ExeDate = "2009/01/05"; WeeksBfReport = 1; DaysBfExecution = 3; Rf = 0.01 };
{ shreshold = 1.5; ReportDate = "2009/12/15"; ExeDate = "2010/01/05"; WeeksBfReport = 2; DaysBfExecution = 2; Rf = 0.01 };
]
let reports = reportsToBeGenerated |> List.map createReport
I'm also not entirely sure what you need (what are other constraints and the motivation), but if you have some interactive code that makes a single calculation, say:
let x = 10
let y = x * x
You can turn it into code that does the same calculation on multiple inputs using e.g. lists:
let xs = [1; 10; 100]
let ys = [ for x in xs -> x * x ]
But as mentioned earlier, it depends on what you actually want to achieve - if you can add a realistic example of what you're trying to do, that would be useful.
Looking at your code you want to do something like this
let run shreshold ReportDate ExeDate WeeksBfReport DaysBfExecution Rf =
//The entire rest of the code indented - you may want to return alpha etc
Then you can just plug in the parameter values
How to modify below code to Return "string" so that returned output displayed on my MVC page and also would like to accept enteredChar from user.
Is there better way to do create this pyramid?
Current code:
let enteredChar = 'F' // As Interactive window doesn't support to Read Input
let mylist = ['A'..enteredChar]
let mylistlength = mylist |> List.length
let myfunc i x tlist1 =
(for j = 0 to mylistlength-i-2 do printf "%c" ' ')
let a1 = [for p in tlist1 do if p < x then yield p]
for p in a1 do printf "%c" p
printf "%c" x
let a2 = List.rev a1
for p in a2 do printf "%c" p
printfn "%s" " "
mylist |> List.iteri(fun i x -> myfunc i x mylist)
Output:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
ABCDEFEDCBA
A few small optimizations could be:
Use StringBuilder instead of printf which is quite slow with long strings.
Use Array instead of List since Array works better with String.
Here is a version producing a pyramid string, which is kept closely to your code:
open System
open System.Text
let generateString c =
let sb = StringBuilder()
let generate i x arr =
String.replicate (Array.length arr-i-1) " " |> sb.Append |> ignore
let a1 = Array.filter (fun p -> p < x) arr
String(a1) |> sb.Append |> ignore
sb.Append x |> ignore
String(Array.rev a1) |> sb.Append |> ignore
sb.AppendLine " " |> ignore
let arr = [|'A'..c|]
arr |> Array.iteri(fun i x -> generate i x arr)
sb.ToString()
generateString 'F' |> printfn "%s"
As an alternative to Daniel's solution, you can achieve what you want with minimal changes to the code logic. Instead of using printf that writes the output to the console, you can use Printf.bprintf which writes the output to a specified StringBuilder. Then you can simply get the resulting string from the StringBuilder.
The modified function will look like this. I added parameter str and replaced printf with Printf.bprintf str (and printfn with bprintf together with additional \n char):
let myfunc i x tlist1 str =
(for j = 0 to mylistlength-i-2 do Printf.bprintf str "%c" ' ')
let a1 = [for p in tlist1 do if p < x then yield p]
for p in a1 do Printf.bprintf str "%c" p
Printf.bprintf str "%c" x
let a2 = List.rev a1
for p in a2 do Printf.bprintf str "%c" p
Printf.bprintf str "%s\n" " "
To call the function, you first create StringBuilder and then pass it to myfunc in every call. At the end, you can get the result using ToString method:
let str = StringBuilder()
mylist |> List.iteri(fun i x -> myfunc i x mylist str)
str.ToString()
I think Daniel's solution looks nicer, but this is the most direct way to tunr your printing code into a string-building code (and it can be done, pretty much, using Search & Replace).
If I understand your question (this likely belongs on Code Review) here's one way to rewrite your function:
let showPyramid (output: TextWriter) lastChar =
let chars = [|'A' .. lastChar|]
let getRowChars n =
let rec loop acc i =
[|
if i < n then let c = chars.[i] in yield c; yield! loop (c::acc) (i+1)
else yield! List.tail acc
|]
loop [] 0
let n = chars.Length
for r = 1 to n do
output.WriteLine("{0}{1}{0}", String(' ', n - r), String(getRowChars r))
Example
showPyramid Console.Out 'F'
or, to output to a string
use output = new StringWriter()
showPyramid output 'F'
let pyramid = output.ToString()
EDIT
After seeing Tomas' answer I realized I skipped over "return a string" in your question. I updated the code and added examples to show how you could do that.
let pyramid (ch:char) =
let ar = [| 'A'..ch |]
let len = ar.Length
Array.mapi
(fun i ch ->
let ar = ar.[0..i]
String.replicate (len - i - 1) " " + new string(ar) + new string((Array.rev ar).[1..]))
ar
|> String.concat "\n"
pyramid 'F' |> printfn "%s"
Here's another approach that seems to be a good demonstration of functional composition. I bet it's the shortest solution among the answers here. :)
let charsToString = Seq.map string >> String.concat String.Empty
let pyramid lastChar =
let src = '-'::['A'..lastChar] |> List.toArray
let len = Array.length src - 1
fun row col -> row-abs(col-len+1)+1 |> max 0 |> Array.get src // (1)
>> Seq.init (len*2-1) >> charsToString // (2)
|> Seq.init len // (3)
pyramid 'X' |> Seq.iter (printfn "%s")
First, we generate an unusual array of initial data. Its element [0] contains a space or whatever separator you want to have; I preferred dash (-) for debugging purposes.
The (1) line makes a function that calculates what character to be placed. The result of row-abs(col-len+1)+1 can be either positive (and there is a char to be placed) or zeronegative, and there should be a space. Note that there is no if statement: it is hidden within the max function;
The (2) line composes a function int -> string for generating an individual row;
The (3) line passes the function above as argument for sequence initializer.
The three lines can be written in a more verbose way:
let genCell row col = row-abs(col-len+1)+1 |> max 0 |> Array.get src
let genRow = genCell >> Seq.init (len*2-1) >> charsToString
Seq.init len genRow
Note genRow needs no formal argument due to functional composition: the argument is being bound into genCell, returning a function of a single argument, exactly what Seq.init needs.