lambdas recursiva em F #
-
05-09-2019 - |
Pergunta
Tome este código de exemplo (ignorá-lo sendo horrivelmente ineficiente para o momento)
let listToString (lst:list<'a>) = ;;' prettify fix
let rec inner (lst:list<'a>) buffer = ;;' prettify fix
match List.length lst with
| 0 -> buffer
| _ -> inner (List.tl lst) (buffer + ((List.hd lst).ToString()))
inner lst ""
Este é um padrão comum Eu continuo vindo através de F #, eu preciso ter uma função interna que em si recurses sobre algum valor - e eu só precisa esta função uma vez, está lá de qualquer maneira possível para chamar um lambda de dentro dele auto (algumas palavras-chave mágica ou algo assim)? Gostaria que o código para algo parecido com isto:
let listToString2 (lst:list<'a>) = ;;' prettify fix
( fun
(lst:list<'a>) buffer -> match List.length lst with ;;' prettify fix
| 0 -> buffer
| _ -> ##RECURSE## (List.tl lst) (buffer + ((List.hd lst).ToString()))
) lst ""
Mas como se poderia esperar não há nenhuma maneira para se referir à função anônima dentro de si, que é necessário que eu coloquei ## RECURSE ##
Solução
Sim, é possível usar os chamados y-combinadores (ou fixed-point combinators
). Ex:
let rec fix f x = f (fix f) x
let fact f = function
| 0 -> 1
| x -> x * f (x-1)
let _ = (fix fact) 5 (* evaluates to "120" *)
Eu não sei artigos para F #, mas isso haskell entrada também pode ser útil .
Mas:. Eu não iria usá-los se houver qualquer alternativa - Eles são muito difíceis de entender
O seu código (omitir as anotações de tipo aqui) é uma construção padrão e muito mais expressivo.
let listToString lst =
let rec loop acc = function
| [] -> acc
| x::xs -> loop (acc ^ (string x)) xs
loop "" lst
Outras dicas
Note que, apesar de você dizer que você use a função apenas uma vez, tecnicamente você se referem a ele pelo nome duas vezes, que é por isso que faz sentido dar-lhe um nome.