Si tratta di un'implementazione ragionevole della funzione quadratica di Bézier in OCaml?
Domanda
Un amico si imbatté in una funzione quadratica B & # 233; zier curve nella sua base di codice che utilizzava un gigantesco ratto nido di una tabella di switch per eseguire il calcolo. Mi ha sfidato a trovare un'unica, breve espressione che gli avrebbe permesso di sostituire il gigantesco blocco di codice.
Nel tentativo di soddisfare due diverse curiosità, ho pensato di provare a implementare la funzione in OCaml. Sono un programmatore OCaml molto alle prime armi e non ho familiarità con la funzione e questa implementazione specifica è difficile da trovare tramite Google.
Sono molto apprezzate le critiche su prestazioni / correttezza della funzione e sulla sua implementazione.
Implementazione di Quadratic B & # 233; zier Curve :
let rec b2 n =
let p1 = -10. in
let p2 = 10. in
let q = n*.n in
let rec b2i n i hd =
if i > n then
List.rev hd
else
let t = i /. n in
b2i n (i+.1.) ((((1.-.t)**2.)*.p1+.(2.*.t*.(1.-.t)*.q)+.(t**2.)*.p2) :: hd)
in b2i n 0. []
;;
let floatprint lst = List.iter (fun f -> Printf.printf "%f; " f) lst ;;
floatprint (b2 8.);;
Soluzione
b2 non è ricorsivo, quindi non è necessario [let rec b2 n =]. Poiché n non cambia mai, non è necessario averlo come argomento per b2i, basta usare n dall'ambito che lo racchiude. La tua funzione interna dovrebbe dipendere da p0, p1 e p2, ma la vedo in base a -10., N ** 2 e 10. La funzione ha anche la forma di una mappa da [0,0; 1.0; 2.0; ...; n.0] ai valori finali. Potresti scriverlo:
let b i =
let t = i /. n in
let tminus = (1.-.t) in
(tminus *. tminus *. p0) +. (2. *. t *. tminus *. p1) +. (t *. t * p2)
in
List.map b ([generate list 1.0; 2.0; ... n.0])
Una funzione per generare l'elenco 1.0 ... n.0 potrebbe essere: (per la piccola n)
let rec count m n = if m > n then [] else m :: (count (m+.1.) n)
Altri suggerimenti
Ho due suggerimenti:
Dovresti chiamare List.rev
dopo i ritorni di b2i
in modo che ocaml possa sfruttare le sue ottimizzazioni di ricorsione della coda. Non sono sicuro di quanto bene Ocaml gestirà l'attuale implementazione, List.rev
è comunque ricorsivo. Noterai che in questo post è fatto come che.
Inoltre, puoi rendere la risoluzione dell'iterazione un argomento facoltativo come ? (epsilon = 0.1)
.
Come programmatore ocaml non vedo molto male qui a parte questo - fintanto che P1 e P2 sono in realtà costanti. Compilalo verso il basso e vedi qual è la differenza nell'assemblaggio tra spostare List.rev all'interno o all'esterno della ricorsione della coda.
Potrebbe essere Picayune, ma hd
non è un buon nome per un parametro di elenco. List.hd
è una funzione standard che restituisce il primo elemento di un elenco. L'uso di hd
come nome per un elenco genererà confusione.