Железнодорожно-ориентированное программирование и частичное применение - PullRequest
5 голосов
/ 19 марта 2019

Мне нравится использовать ROP, когда мне приходится иметь дело со строками ввода-вывода / синтаксического анализа /...

Однако, скажем, у меня есть функция, принимающая 2 параметра.Как вы можете сделать чистое / читаемое частичное приложение, если ваши 2 параметра уже являются Результатом <'a,' b> (не обязательно то же самое, что и 'a,' b)?

Пока что я делаю, что яиспользуйте tuple для передачи параметров и используйте функцию ниже, чтобы получить Result of the tuple, чтобы я мог затем связать свою функцию с этим «tuple-параметром».

/// Transform a tuple of Result in a Result of tuple
let tupleAllResult x =
    match (fst x, snd x) with
    | Result.Ok a, Result.Ok b    -> (a,b) |> Result.Ok
    | Result.Ok a, Result.Error b -> b |> Result.Error
    | Result.Error a, _           -> a |> Result.Error

let f (a: 'T, b: 'U) = // something

(A, B) |> tupleAllResult
       |> (Result.bind f)

Любая хорошая идея?

Вот то, что я написал, которое работает, но не может быть самым элегантным

let resultFunc (f: Result<('a -> Result<'b, 'c>), 'd>) a =
    match f with
    | Result.Ok g    -> (g a) |> Result.Ok |> Result.flatten
    | Result.Error e -> e |> Result.Error  |> Result.flatten

1 Ответ

7 голосов
/ 19 марта 2019

Я не вижу частичного применения в вашем примере, концепции, связанной с каррированием и передачей аргументов - поэтому я предполагаю, что вы следуете за монадическим apply, в том, что вы хотите преобразовать функцию, обернутую в значение Result, в функцию, которая принимает Result и возвращает другое Result.

let (.>>.) aR bR = // This is "tupleAllResult" under a different name
    match aR, bR with
    | Ok a, Ok b -> Ok(a, b)
    | Error e, _ | _, Error e -> Error e
// val ( .>>. ) : aR:Result<'a,'b> -> bR:Result<'c,'b> -> Result<('a * 'c),'b>

let (<*>) fR xR = // This is another name for "apply"
    (fR .>>. xR) |> Result.map (fun (f, x) -> f x)
// val ( <*> ) : fR:Result<('a -> 'b),'c> -> xR:Result<'a,'c> -> Result<'b,'c>

Разница с тем, что у вас есть в вопросе, map вместо bind в последней строке.

Теперь вы можете начать lift функций в мире Result:

let lift2 f xR yR =
    Ok f <*> xR <*> yR
// val lift2 :
//   f:('a -> 'b -> 'c) -> xR:Result<'a,'d> -> yR:Result<'b,'d> -> Result<'c,'d>

let res : Result<_,unit> = lift2 (+) (Ok 1) (Ok 2) 
// val res : Result<int,unit> = Ok 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...