If you really don't want to do this the purely functional way (carrying all state), e.g. if it is for a GUI, then you might want to mimic a mutable data structure and trigger events upon mutation.
Cheers,
Jon.
Is the transform function point-wise? I.e., does an element in the output array only depend on its corresponding element in the input array? If so you might be able to do something simple with IEnumerables where your transform function is something like Seq.map.
To get around the performance problem you identified with ObservableCollection you can, instead of computing updates when input it written, compute updates when output is read. So when input it added it just adds it to a data structure and triggers no events. Then when output is retrieved it first checks if new input has been added and does an update if necessary.
Hope this helps.
- Greg
Hi,
Thanks for the reply. I had thought about using container structures at first, like having
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
type foo = class //x.update computes marginally-needed output values //x.can_compute returns true if : arguments are valid AND there is enough data to perform computations member x.output = match x._output with | Some x -> Some x | None -> if x.can_compute() then x.update() ; x.output else None end
However, the disadvantage is that the <update> and <can_compute> functions should be hidden from the end-user (i.e. they should be "protected"), which is possible if you define your base class in the same file as the implementation of the classes, but it prevents later extension (adding new functions in other classes).
Did you have something different in mind ?
I have included a few examples below. I am not sure how you could use a map to define an output function that references itself.
Thanks again for your kind help !
Julien
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
#light module Transform module ResizeArray = begin let is_empty (arr:ResizeArray<'a>) = arr.Count = 0 let empty () = new ResizeArray<_>() let fill_f (arr:ResizeArray<'a>) start len f = for i in start .. start + len - 1 do arr.[i] <- f i let add (arr:ResizeArray<'a>) value = arr.Add value let clear (arr:ResizeArray<'a>) = arr.Clear() //taken from the FSLib/ResizeArray.fs source file let to_array (arr:ResizeArray<'a>) = Seq.to_array arr let of_array (arr:array<'a>) = new ResizeArray<_>(Seq.of_array arr) end (*******************************************************************************************************************************) (*******************************************************************************************************************************) // Example of a simple function that could be used used with a "map input f" but that is a little more rapid this way //Minimum let minimum data periods = //input verification let check_errors() = if data = null then invalid_arg "<min> : data is null" if periods <= 0 then invalid_arg "<min> : periods<=0" //output structure let result = new ResizeArray<float>() //computation helpers let data_length() = ResizeArray.length data let enough_data() = data_length() >= periods let start_index() = ResizeArray.length result + periods - 1 let current_min_idx = ref 0 let find_min_idx end_idx = let mutable idx = end_idx for i in (end_idx - periods + 1) .. (end_idx-1) do if data.[i] < data.[idx] then idx <- i idx let compute data_idx = if data_idx - periods >= !current_min_idx then current_min_idx := find_min_idx data_idx else if data.[data_idx] < data.[!current_min_idx] then current_min_idx := data_idx data.[!current_min_idx] //update function let update() = check_errors() if enough_data() then for data_idx in start_index() to data_length() - 1 do ResizeArray.add result (compute data_idx) update() result, update (*******************************************************************************************************************************) (*******************************************************************************************************************************) //Example of a function that outputs values which depend on the previously output values //Exponential Moving Average let ema data periods = //input verification let check_errors() = if data = null then invalid_arg "<ema> : data is null" if periods <= 0 then invalid_arg "<ema> : periods<=0" //output structure let result = new ResizeArray<float>() //computation helpers let data_length() = ResizeArray.length data let enough_data() = data_length() >= periods let start_index() = ResizeArray.length result + periods - 1 let periods_f = float_of_int periods let k = 2.0 / (1.0 + periods_f) let compute data_idx = let offset = data_idx - periods result.[offset] + (k * (data.[data_idx] - result.[offset])) //update function let update() = check_errors() if enough_data() then if ResizeArray.length result = 0 then ResizeArray.add result 0.0 for data_idx in 0 .. periods-1 do result.[0] <- result.[0] + (data.[data_idx]/periods_f) for data_idx in start_index() to data_length() - 1 do ResizeArray.add result (compute data_idx) update() result, update (*******************************************************************************************************************************) (*******************************************************************************************************************************) //Example of the current composition issue // //I start by defining a function <gema> //I then use it in another function which could be defined as let bar = gd >> gd >> gd //it could... if we didn't return an <update> function //Generalized Double Exponential Moving Average let gdema data periods factor = try //component of the transform let ema_, update_ema = ema data periods let ema_of_ema, update_ema_of_ema = ema ema_ periods //output structure let result = new ResizeArray<float>() //computation helpers let data_length() = ResizeArray.length data let enough_data() = data_length() >= periods + periods - 1 let start_index() = ResizeArray.length result + 2 *(periods - 1) let one_plus_factor = 1.0 + factor let compute data_idx = let offset_ema = data_idx - periods + 1 let offset_ema_of_ema = offset_ema - periods + 1 (ema_.[offset_ema] * one_plus_factor) - (ema_of_ema.[offset_ema_of_ema] * factor) //update function let update() = update_ema() update_ema_of_ema() if enough_data() then for data_idx in start_index() to data_length() - 1 do ResizeArray.add result (compute data_idx) update() result, update with e -> invalid_arg ("<gdema> -> " ^ e.Message) //Composed function //T3 let t3 data periods volume_factor = try //computation helpers let gd, update_gd = gdema data periods volume_factor let gd_of_gd, update_gd_of_gd = gdema gd periods volume_factor let result, update_gd_of_gd_of_gd = gdema gd_of_gd periods volume_factor //update function let update() = update_gd() update_gd_of_gd() update_gd_of_gd_of_gd() update() result, update with e -> invalid_arg ("<t3> -> " ^ e.Message)
Since to compute the next point of exponential moving average requires only the last output value and current input value you can write it as a transform function over seq's like this
1 2 3 4 5 6 7 8 9
let ema period (inp : #seq<double>) = let sum xs = fold (fun s x -> s + x) 0 xs let head = truncate period inp let tail = drop period inp let start = (sum head) / period let k = 2.0 / (1.0 + period) let update last_outp curr_inp = last_outp + k * (curr_inp - last_outp) scan update start tail
Where 'drop' is the opposite to 'truncate': it drops the first n elements from a seq. Now you can compose 'ema n' with itself. You can do the same for minimum too but it's a bit harder because you need to carry more complex state between outputs.
Using seq to move data around is very convenient but it may not be suitable depending on how the data is generated and consumed in your application.
- Greg
Thanks for your help. I'll probably go throgh the use of "static" seq.
I have a question however, regarding the following piece of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
let medprice (h :> seq<float>) (l :> seq<float>) = //input verification let check_errors() = if h = null || l = null then invalid_arg "<medprice> : at least one of h and l is null" let len_h = Seq.length h if len_h <> Seq.length l then invalid_arg "<medprice> : h and l don't have the same length" else let i = ref (-1) let check h l = incr i ; if h < l then invalid_arg ("<medprice> : h and l are not consistent (h >= l), see for instance at position " ^ (string_of_int !i)) Seq.iter2 check h l check_errors() let compute h l = (h+l)/2.0 Seq.map2 compute h l
When I send it to fsi, it refuses to accept float arrays as inputs, while float arrays should be constrainable to seq<float> (it does work with your ema function). Notwithstanding the signature shown in Intellisense is of type
1
^a when ^a : null and ^a :> seq<float>
.
Any idea?
Thanks a lot for your help !
FWIW (ie not much), here are a few fnuctions I used along the way
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
(*******************************************************************************************************************************) // Existing Modules Extensions (*******************************************************************************************************************************) module IEnumerator = begin open System.Collections.Generic let iter3 f (e1 :> IEnumerator<'a>) (e2 :> IEnumerator<'b>) (e3 :> IEnumerator<'c>) = while ( let n1 = e1.MoveNext() let n2 = e2.MoveNext() let n3 = e3.MoveNext() if n1 <> n2 || n1 <> n3 then invalid_arg "Seq.iter3: the collections have different lengths"; n1 ) do f e1.Current e2.Current e3.Current done let iter4 f (e1 :> IEnumerator<'a>) (e2 :> IEnumerator<'b>) (e3 :> IEnumerator<'c>) (e4 :> IEnumerator<'d>) = while ( let n1 = e1.MoveNext() let n2 = e2.MoveNext() let n3 = e3.MoveNext() let n4 = e4.MoveNext() if n1 <> n2 || n1 <> n3 || n1 <> n4 then invalid_arg "Seq.iter4: the collections have different lengths"; n1 ) do f e1.Current e2.Current e3.Current e4.Current done end module Seq = begin open System.Collections.Generic open Seq let drop n (x :> seq<'a>) = assert (n >= 0) generate ( fun () -> ref 0, x.GetEnumerator()) ( fun (i, ie) -> let rec take() = if not (ie.MoveNext()) then None else if !i < n then incr i take() else Some ie.Current take() ) ( fun (_,ie) -> ie.Dispose() ) let iter3 f (ie1 :> IEnumerable<'a>) (ie2 :> IEnumerable<'b>) (ie3 :> IEnumerable<'c>) = using (ie1.GetEnumerator()) (fun ie1 -> using (ie2.GetEnumerator()) (fun ie2 -> using (ie3.GetEnumerator()) (fun ie3 -> IEnumerator.iter3 f ie1 ie2 ie3))) let iter4 f (ie1 :> IEnumerable<'a>) (ie2 :> IEnumerable<'b>) (ie3 :> IEnumerable<'c>) (ie4 :> IEnumerable<'d>) = using (ie1.GetEnumerator()) (fun ie1 -> using (ie2.GetEnumerator()) (fun ie2 -> using (ie3.GetEnumerator()) (fun ie3 -> using (ie4.GetEnumerator()) (fun ie4 -> IEnumerator.iter4 f ie1 ie2 ie3 ie4)))) end
Hi Julien,
The first problem you mentioned relates to the use of "null" equality checks. When you mouse-hover over "medprice" you see the type
1 2 3 4
seq<float> -> seq<float> -> seq<float>
To be usable at mutliple types you would want to see:
1 2 3 4
#seq<float> -> #seq<float> -> seq<float>
Which you see if you delete the lines
1 2
if h = null || l = null then invalid_arg "<medprice> : at least one of h and l is null"
Equality checking is not the recommended technique for checking for nulls, especially against polymorphic values. (The "#seq<_>" representa a polymorphic value with a constraint that it implements the seq<_> interface). Instead I recommend you use the following:
1 2 3 4 5 6 7 8 9 10 11
let isNull (x:'a) = match box x with null -> true | _ -> false ... if isNull h || isNull l then invalid_arg "<medprice> : at least one of h and l is null"
Your problem then goes away, because we're not requriing the the polymorphic input support "null", which was the cause of your loss of polymorphism.
I'll add this to the Expert F# book.
Don
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
Hi,
I have a very general programming question. It basically contains a few functions which transfom some input data into output values (the transforms consist in smoothing etc.)
These transform functions ought to be used in either a static environment (for instance, when doing some backtesting), but also in a dynamic (or real-time, so to speak) environment (for instance, when receiving data from whatever data provider you use).
The functions are currently of the type : [
](where the basic structure of the input data is ResizeArray<_>, and the output is either a ResizeArray<_> or a tuple of those.
The <update function>, when called, performs computations from where the initial call to the transformation function left on (using the initial arguments). That is, say you have 20 observations to start with, and then add 10 more observations to your input data, then update() performs the transform (adding values to the output data structure) for those 10 values only (it doesn't recompute from scratch).
The issue wih returning both an output AND an update function, is that you can't compose functions that easily. Indeed, you can't simply have [
]which you could have if foo only returned result.
I thought about using the ObservableCollection from WPF (where, basically, I would use something (very) roughly like : input.OnAddValue.Add (fun _ -> update()) . However, this means that every update of the input data causes an update of the transformed values collection, which you might not want (that is, it doesn't seem stupid to only want to compute the update every n (milli)seconds instead to save CPU / do other stuff in the mean time).
I had also thought on recomputing the whole output from scratch on every update, but this should probably be overkill.
My question is therefore : is there a preferred/common way to deal with the dynamic aspect?
Any insight/advice would be appreciated.
Cheers,
Julien