iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0

C#中的Task物件其實可以視為一個Monad,今天要介紹Task的一些特性,並且幫它補上擴充方法。

Task Monad

觀察Task物件,我們可以知道兩件事情

  1. Task 表示一段非同步作業,預期作業完成時會回傳T型別的值
  2. 使用await可以等待作業完成

我們可以將Task視為一個包裹了T的盒子,是不是有點像Monad了呢?接下來我們要來幫它實做Return/Map以及Bind

Return

public static Task<T> Return<T>(T source) => Task.FromResult(source);

Return很簡單,當我們希望把一個值放到Task裡面的時候直接使用Task.FromResult就好

Map

public static async Task<TResult> Map<TSource,TResult>(this Task<TSource> source, Func<TSource,TResult> f)
 => f(await source);

當我們要取出Task裡面的值時,只要使用await就可以了,不過也因為使用到await的關係,Map需要加上async修飾詞。

Bind

public static async Task<TResult> Bind<TSource,TResult>(this Task<TSource> source, Func<TSource,Task<TResult>> f)
 => await f(await source);

注意一下Bind所接受的Func,需要回傳一個Task,所以除了要用await取得source內部的值以外,也需要取的整個Func的結果。

Monad Laws

接下來我們可以檢查這樣設計是不是滿足Monad的條件

  1. Left identity

    var s = Return("Hello"); // Task<string> with "Hello"
    s.Bind(x => Return(x)); // Task<string> with "Hello"
    

    在Bind中我們會先取得x=”Hello”,然後再次將Hello放入Task中。

  2. Right identity

    var s = Return("Hello"); 
    s.Bind(x => Return(x+" World"));  // Task<string> with "Hello World"
    

    很顯然也滿足第二條

  3. Associativity

    var s = Return("Hello"); 
    s.Bind(x => Return(x + " World"))
     .Bind(x => Return(x + "!")); // Hello World!
    
    s.Bind(x => Return(x + await Return(" World" + "!"))); // Hello World!
    

    這樣代表也滿足了結合律

小結

Task具有Monad的特性,明天我們來討論如何利用這樣的特性去設計非同步的程式。


上一篇
Day17. Monad(2)
下一篇
Day19. Task(2)
系列文
Functional Programming with C#30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言