É este uma implementação razoável da função Bézier quadrática em OCaml?
Pergunta
Um amigo veio através de uma função de curva Bézier quadrática em sua base de código que usou uma ratos gigantesco ninho de uma mesa interruptor para executar o cálculo. Ele desafiou-me a encontrar uma única expressão, curta que permitiria a ele para substituir o bloco gigantesco de código.
Na tentativa de satisfazer duas curiosidades diferentes, eu pensei que eu ia tentar implementar a função em OCaml. Eu sou um muito novato programador OCaml e eu também estou familiarizado com a função e este específica implementação é difícil passar por aqui via Google.
As críticas, tanto da função performance / correção, bem como a sua implementação são muito apreciado.
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.);;
Solução
b2 não é recursivo, assim não há necessidade para [deixar b2 rec n =]. Desde n nunca muda, não há necessidade de tê-lo como argumento para B2I, basta usar n do âmbito de inclusão. Sua função interna deve depender P0, P1 e P2, mas eu vejo isso dependendo -10, n ** 2 e 10. A função também tem a forma de um mapa de [0.0.; 1,0; 2,0; ...; n.0] para os valores finais. você poderia escrevê-lo:
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])
Uma função para gerar a lista 1.0 ... n.0 poderia ser: (para pequenas n)
let rec count m n = if m > n then [] else m :: (count (m+.1.) n)
Outras dicas
Eu tenho duas sugestões:
Você deve chamar List.rev
após b2i
retornos tão ocaml pode explorá-la de otimizações cauda-recursão. Não estou certo de quão bem ocaml vai lidar com a implementação atual, List.rev
é, porém cauda-recursivo. Você vai notar que em este post é feito como isso.
Além disso, você pode fazer a resolução da iteração ser um argumento opcional como ?(epsilon=0.1)
.
Como um programador ocaml eu não vejo muito errado aqui além de que --como desde que P1 e P2 estão em constantes fatos. Compilá-lo para baixo e ver o que a diferença de montagem é entre mover List.rev dentro ou para fora da cauda-recursão.
Isto pode ser picuinhas, mas hd
não é um nome bom para um parâmetro lista. List.hd
é uma função padrão que retorna o primeiro elemento de uma lista. Usando hd
como um nome para a lista vai levar a confusão.