Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coroutines in F#

I'm just getting started with Unity3D using F# and I'm noticing that coroutines are used heavily in books and tutorials as a neat solution for solving a variety of problems. I've been trying to figure out whether or not F# has the equivalent built-in constructs, or if it's at least possible to somehow mimic them, but I can't find anything on MSDN. I only found a few articles with implementations of coroutines using a Continuation monad, but these are way over my head as a beginner.

Here's the C# example from the Unity docs, which when called repeatedly inside the game loop results in fading the object's alpha color in small increments over time:

IEnumerator Fade() {
    for (float f = 1f; f >= 0; f -= 0.1f) {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield return;
    }

}

So I simply have to declare a function that returns an IEnumerator, then cede control wherever I want to inside the body with a "yield." I'm not sure how to do this in F# as I keep getting the error "This expression was expected to have type IEnumerator but here has type unit". The "yield" keyword also seems to behave differently in F# since unlike C# it cannot be used on its own and has to be inside a sequence expression as I understood from the docs.

So am I missing anything? How would the functionality above be implemented in F#?


UPDATE

Gustavo's explanation is correct. Here is the exact Unity script which you can attach to an object to see it's Red color value decrease by 0.1 over a 10 second time frame.

namespace CoroutinesExample
open UnityEngine

type CoroutinesExample() =
    inherit MonoBehaviour()

    member this.Start() =
        // Either of the these two calls will work
        // this.StartCoroutine("Fade") |> ignore
        this.Fade()                       

    member this.Fade() =
       seq { 
           for f in 1.f .. -0.1f .. 0.f do 
               let mutable c = this.renderer.material.color
               c.r <- f 
               this.renderer.material.color <- c
               yield WaitForSeconds(1.f) 
       } :?> IEnumerator

This article was very helpful in explaining the details of coroutines in Unity.

like image 728
user2959993 Avatar asked Mar 22 '23 18:03

user2959993


1 Answers

The equivalent F# code is the following:

member this.Fade() =
    seq {
        for f in 1.0 .. -0.1 .. 0.0 do
            let c = renderer.material.color
            c.alpha <- f
            renderer.material.color <- c
            yield ()
    } :> IEnumerable

Note that unlike in C#, you have to yield some value, so we're using unit (()). The seq expression will have the type seq<unit>, which is an alias for IEnumerable<Unit>. To make it conform to the type Unity is expecting, we just need to upcast it by using :> IEnumerable

like image 163
Gustavo Guerra Avatar answered Mar 28 '23 14:03

Gustavo Guerra