Вопрос

Обновлен После очевидной ошибки указывала Джон Палмер в комментариях.

Следующий код приводит к генеракодичеству:

let agent = MailboxProcessor<string>.Start(fun agent ->

    let maxLength = 1000

    let rec loop (state: string list) i = async {
        let! msg = agent.Receive()

        try        
            printfn "received message: %s, iteration: %i, length: %i" msg i state.Length
            let newState = state |> Seq.truncate maxLength |> Seq.toList
            return! loop (msg::newState) (i+1)
        with
        | ex -> 
            printfn "%A" ex
            return! loop state (i+1)
    }

    loop [] 0
)

let greeting = "hello"

while true do
    agent.Post greeting
    System.Threading.Thread.Sleep(1) // avoid piling up greetings before they are output
.

Ошибка исчезла, если я не использую блок TRY / CALL.

Увеличение времени сна только отложить ошибку.

Обновление 2: Я предполагаю, что проблема здесь заключается в том, что функция останавливается, будучи хвостом рекурсивным, поскольку рекурсивный вызов больше не является последним для выполнения.Было бы здорово для кого-то с большим количеством F # опытом, чтобы Desugar это, как я уверен, это обычная ситуация с утечкой памяти в агентах F #, поскольку код очень прост и универсальный.

Это было полезно?

Решение

<Сильное> Решение:

оказалось частью большей задачи: функция не может быть рекурсивным хвостом, если рекурсивный вызов сделан в блоке Thrue / Catch, так как он должен быть в состоянии развернуть стек, еслиИсключение брошено и, таким образом, необходимо сохранить информацию стека вызовов.

<Сильные> Подробнее Здесь:

Хвостовое рекурсирование и исключения в F #

Правильно переписанный код (отдельная попытка / улов и возврат):

let agent = MailboxProcessor<string>.Start(fun agent ->

    let maxLength = 1000

    let rec loop (state: string list) i = async {
        let! msg = agent.Receive()

        let newState = 
            try        
                printfn "received message: %s, iteration: %i, length: %i" msg i state.Length
                let truncatedState = state |> Seq.truncate maxLength |> Seq.toList
                msg::truncatedState
            with
            | ex -> 
                printfn "%A" ex
                state

        return! loop newState (i+1)
    }

    loop [] 0
)
.

Другие советы

I suspect the issue is actually here:

while true do
    agent.Post "hello"

All the "hello"s that you post have to be stored in memory somewhere and will be pushed much faster than the output can happen with printf

See my old post here http://vaskir.blogspot.ru/2013/02/recursion-and-trywithfinally-blocks.html

  • random chars in order to satisfy this site rules *

Basically anything that is done after the return (like a try/with/finally/dispose) will prevent tail calls.

See https://blogs.msdn.microsoft.com/fsharpteam/2011/07/08/tail-calls-in-f/

There is also work underway to have the compiler warn about lack of tail recursion: https://github.com/fsharp/fslang-design/issues/82

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top