iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0

今天要討論錯誤處裡,我們在前面介紹了Option型別來解決函數沒有對應的問題,但有的時候我們除了沒有對應結果外,可能需要其他的訊息,像是什麼輸入沒有結果,或者是沒有結果的原因。當程式發生意外造成沒有結果的時候,我們通常會用throw exception的方式,前面也有提到微軟建議的拋出例外的方法。然而並不是所有情況都適合拋出例外,比如說大量的資料流時我們更傾向於讓流程繼續進行,最後才把有異常的資料額外處理

如果成功的話就做A,失敗的話就做B

記不記得前幾天我用過tuple包裝Int.TryParse的結果

(bool IsInt, int number, string oper) ParseInt(string s)
{
    var isInt = int.TryParse(s, out var n);
    return (isInt, n, s);
}

針對這個函數的回傳,如果IsInt是ture的話我就取得轉換後的數字,如果是false的話就將文字取出來判斷需要做什麼操作,這種”如果成功就的到A,如果失敗就得到B”其實是一種蠻常見的抽象,在FP中有定義了一個型別Either善於處裡這種事,可以仿照一下Option

public class Either
{
    public static Either Left<L>(L data) => new Left<L>(data);
    public static Either Right<R>(R data) => new Right<R>(data);
}

public class Right<R> : Either
{
    public Right(R data) => this.Data = data;
    public R Data { get; init; }
}

public class Left<L> : Either
{
    public Left(L data) => this.Data = data;
    public L Data { get; init; }
}

然後我們就可以針對Either型別設計他的HOF

public static class EitherExtension
{
    public static Either Bin<RS, RR, LS, LR>(this Either e, Func<RS, RR> Right, Func<LS, LR> Left)
        => e switch
        {
            Right<RS> { Data: var data } => Either.Right(Right(data)),
            Left<LS> { Data: var data } => Either.Left(Left(data)),
            _ => throw new NotSupportedException()
        };
}

這邊是不是開始覺得patten match的寫法很神奇呢?Either型別具有兩個元素,其中Right表示對,Left表示錯誤,再利用函子去設計對應的處裡。有了Either型別,前幾天對於TryParse就會變成了


var array = input.Split(' ') 
								 .Select(ParseInt);
								 .Aggregate(new Stack<int>(), Compute)
								 .First();

ImmutableStack<int> Compute(ImmutableStack<int> stack, Either s)
    => s switch
		{
			Right<int> { Data: var n } => stack.Push(n),
			Left<string> { Data: var o } => Operate(stack, o)
		    _ => throw new NotSupportedException()
		}

Either ParseInt(string s)
    => int.TryParse(s, out var n)
        ? Either.Right(n)
        : Either.Left(s);

Left的內容就可以放入錯誤訊息,不管是用例外物件甚至是物件的陣列,在最後統一彙整。

小結

有了前面的介紹,其實Either跟Option的概念非常相似,只是針對回傳值保留更多彈性讓我們處理,介紹Either是為了對之後要討論的如何處理純函數與不純函數做鋪墊,但明天會先討論monad。


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

尚未有邦友留言

立即登入留言