簡體   English   中英

為什么簽名會...... - &gt;結果 <char*string> ?

[英]Why would the signature be … -> Result<char*string>?

我正在關注斯科特的講話 ,他帶來的一個例子是:

type Result<'a> = 
    | Success of 'a
    | Failure of string
let pchar (charToMatch, input) =
    if System.String.IsNullOrEmpty (input) then
        Failure "no input!"
    else
        let first =  input.[0]
        if  first = charToMatch then
            let remaining = input.[1..]
            Success (charToMatch, remaining)
        else
            let msg = sprintf "exepecting '%c' got '%c'" charToMatch first
            Failure msg

Visual Studio Code顯示pchar函數的簽名是:

char*string->Result<char*string>

vscode截圖

返回類型應該只是Result<'a>嗎?

Result<'a>是一個泛型類型,它具有'a作為類型參數。 當您編寫Success (charToMatch, remaining)編譯器會將此泛型類型參數推斷為charstring的元組: Result<char*string> 您可以編寫Success ()然后您將獲得Result<unit>類型。

同樣在F#中,當您使用逗號(charToMatch, input)在括號中列出函數的參數時,這意味着您的函數期望一個元組,這意味着您不能使用currying 要使let pchar charToMatch input = ...可用,你應該定義這樣的函數: let pchar charToMatch input = ...

這里的想法是您可以使用Result類型來包裝任何操作的結果,以便您可以使用業務邏輯對控制流進行建模。 這在“業務錯誤”和“例外”之間存在重疊的情況下尤其有用。 在您的示例中,一次解析一個字符串,並且該函數返回解析后的字符以及字符串的其余部分(作為F#Tuple)。

Result是泛型類型,因此它可以表示任何操作的結果。 如果Result類型的'a type-parameter的值不返回Result則它將與函數的返回類型相同。 考慮一個如下的簡單示例:

let f () = ('t', "est")

編譯器告訴我們它有類型簽名unit -> char * string 那是因為函數總是采用一個unit (空/無效)參數並返回一個單個字符和一個字符串的元組。 如果我們稍微更改該函數以返回Result ,如下所示:

let f () = ('t', "est") |> Success

現在編譯器告訴我們簽名是unit -> Result<char * string> 與函數的原始返回類型相同,包含在Result類型中。 您的示例是相同的,除了返回的字符和字符串元組基於輸入參數,並且如果輸入參數為null或空字符串,則函數可以返回失敗。

如果定義一個“解包”結果並將其中的值傳遞給另一個函數的bind函數,則可以輕松使用Result類型, f

let bind f = function
| Success s -> f s
| Failure f -> Failure f

使用bind ,您可以輕松地將pchar調用的結果傳遞給另一個使用該值的函數,而該函數不必顯式獲取Result類型:

let printChar (c, str) =
    printfn "Matched Char %A, Remaining String: '%s'" c str

pchar ('a', "aaab") |> bind (printChar >> Success)

我經常使用這種模式,但是我在Result類型中添加了第二個泛型參數,表示函數的eventseffects 這通過允許我們具有可以在代碼中處理的特定Failure事件(而不是檢查特定字符串),或通過包含域事件(例如警告)或副作用以及我們的成功結果來增加Result類型的效用。

我為此使用了一個名為OperationResult的類型,以避免與內置的F# Result類型混淆。 由於我有時會包含事件/效果成功結果以及失敗,因此我為SuccessfulResult定義了一個類型,它只是返回值,或返回值以及事件列表。 總之,它提供了以下類型來定義OperationResult

/// Represents the successful result of an Operation that also yields events
/// such as warnings, informational messages, or other domain events
[<Struct>]
type SuccessfulResultWithEvents<'result,'event> =
    {
        Value: 'result
        Events: 'event list
    }

/// Represents the successful result of an Operation,
/// which can be either a value or a value with a list of events
[<Struct>]
type SuccessfulResult<'result,'event> =
    | Value of ResultValue: 'result
    | WithEvents of ResultWithEvents: SuccessfulResultWithEvents<'result,'event>
    member this.Result =
        match this with
        | Value value -> value
        | WithEvents withEvents -> withEvents.Value
    member this.Events =
        match this with
        | Value _ -> []
        | WithEvents withEvents -> withEvents.Events    


/// Represents the result of a completed operation,
/// which can be either a Success or a Failure
[<Struct>]
type OperationResult<'result,'event> =
    | Success of Result: SuccessfulResult<'result,'event>
    | Failure of ErrorList: 'event list

如果您想使用它,我將所有這些打包在GitHub (和NuGet )的庫中以及稱為operation的Computation Expression中。 GitHub頁面也有一些例子。

@kagetoki是正確的,F#從使用中推斷出類型。

此外,這看起來像一個解析器組合庫。 pchar的目的是嘗試從輸入中提取字符。 如果成功返回字符和字符串的其余部分,則表示char*string的自然方式。 這包含在Result以支持失敗,因此最終返回類型應為: Result<char*string>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM