在fp-ts和函数式编程中管理monad数组 [英] Managing array of monads in fp-ts and Functional Programming

查看:119
本文介绍了在fp-ts和函数式编程中管理monad数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对函数式编程非常陌生,我在数组上遍历很费劲。



当我阅读这本书看来我应该能够简单地在Monad之间来回走动,但是我无法用 fp-ts



有人可以使用 array.traverse / sequence 或其他任何方式解释以下内容吗?


  1. 如何从 TaskEither< Error,string []> 转到 TaskEither< Error,Either< Error,string> []> ;还是有一种更好的方法可以使单个错误变为嵌套错误,同时又使输入保持简单?

  2. 如何从 TaskEither< Error,Either< Error ,string []>> 到类似 TaskEither< Error,Option< string []>> 之类的东西;还是应该映射该函数的结果以返回到 c?

考虑以下简化代码,以更好地了解我们对这些数组的处理方式:

  //辅助函数
声明函数toItems(input:string):TaskEither< Error,string []);
声明函数toTitle(item:string):要么<错误,字符串> ;;
声明函数clean(item:string):Option< string> ;;

//这是我到目前为止尝试过的
const program =(input:string)=> pipe(
toItems(input),//我们有TaskEither< Error,string []>
TE.map(items => array.traverse(two)(items,toTitle)),/ /现在我们有了TaskEither< Error,Either< Error,string []>>
TE.map(items => array.traverse(option)(items,clean)),//清理都不起作用()从这里


解决方案

严格地说,适用足以满足遍历-您不需要单子。


TaskEither<错误,字符串[ ]> TaskEither< Error,Either< Error,string> []>



  const program1 =(输入:字符串)=> 
P.pipe(
toItems(input),
TE.map(A.map(toTitle))
);



TaskEither< Error,Either< Error,string []> ;> TaskEither< Error,Option< string []>



  const program2 =(输入:字符串)=> 
P.pipe(
toItems(input),
TE.map(item => A.array.traverse(O.option)(items,clean))
) ;

具体选择的结构取决于您的环境和目的。 ▶选项:强调缺席/在场; ▶任一个:允许在中使用更具体的错误类型。




让我们看一些程序,然后想象一下,所有程序都使用带有 TaskEither 的Web API。


程序3:(输入:字符串)=> TE.TaskEither< Error,string []>

▶将完全失败,并出现 Error 或以 string [] 提取的数据成功


程序4:(input:string)=> TE.TaskEither< Error,E.Either< Error,string []>>

fetch 会导致错误或成功。如果成功,则进一步处理Web数据-导致错误 字符串[]


程序5:(输入:字符串)=> TE.TaskEither<错误,E.Either<错误,字符串> []>

▶与计划4相同,但对Web数据的后处理导致多个 任何一个结果-每个可以失败或成功




这是程序4的某种中间立场:

  const program4 =(
输入:字符串
):TE.TaskEither<错误,E.Either<错误,string []> =>
P.pipe(
toItems(input),// TE.TaskEither<错误,string []>
TE.map(items => // TE.TaskEither< E, E.Ether<错误,string []>
A.array.traverse(E。任一)(// E.Either<错误,string []>
项目,
F.flow(// E.Ether< Error,string>
toTitle,
E.chain(s => E.fromOption(()=> Error())(clean(s )))



);

代码框


I'm very new to Functional Programming and I'm struggling a lot with running traverse on arrays.

When I read this book it seems that I should be able to simply traverse between Monads but I can't wrap my head around this concept with fp-ts.

Can someone explain the following using array.traverse/sequence or any other ways please?

  1. How can I go from TaskEither<Error, string[]> to TaskEither<Error, Either<Error, string>[]>; or is there a better way to go from a single error to nested errors while keeping the typings simple?
  2. How can I go from TaskEither<Error, Either<Error, string[]>> to something like TaskEither<Error, Option<string[]>> or something similar; or should we map the result of that function to turn back to Either?

Consider the following simplified code to have a better idea what we are doing with these arrays:

// helper functions
declare function toItems(input: string): TaskEither<Error, string[]);
declare function toTitle(item: string): Either<Error, string>;
declare function clean(item: string): Option<string>;

// This is what I tried so far
const program = (input: string) => pipe(
  toItems(input), // we have TaskEither<Error, string[]>
  TE.map(items => array.traverse(either)(items, toTitle)), // now we have TaskEither<Error, Either<Error, string[]>>
  TE.map(items => array.traverse(option)(items, clean)), // nothing works with clean() from here
)

解决方案

Strictly spoken, Applicative is sufficient for traverse - you don't need a monad.

TaskEither<Error, string[]> to TaskEither<Error, Either<Error, string>[]>?

const program1 = (input: string) =>
  P.pipe(
    toItems(input),
    TE.map(A.map(toTitle))
  );

TaskEither<Error, Either<Error, string[]>> to TaskEither<Error, Option<string[]>>?

const program2 = (input: string) =>
  P.pipe(
    toItems(input),
    TE.map(items => A.array.traverse(O.option)(items, clean))
  );

The concrete chosen structure depends your environment and purpose. ▶ Option: emphasis on absence/presence ; ▶ Either: permits a more concrete error type in Left.


Let's look at some programs and imagine, all use a web API with TaskEither.

Program 3: (input: string) => TE.TaskEither<Error, string[]>

▶ will either fail completely with Error or succeed with string[] fetched data

Program 4: (input: string) => TE.TaskEither<Error, E.Either<Error, string[]>>

fetch results in Error or succeeds. If succeeded, process web data further - resulting in Error or string[]

Program 5: (input: string) => TE.TaskEither<Error, E.Either<Error, string>[]>

▶ same as Program 4, but post-processing of web data results in multiple Either results - each can fail or succeed individually


Here is implementation of program 4 as some kind of middle ground:

const program4 = (
  input: string
): TE.TaskEither<Error, E.Either<Error, string[]>> =>
  P.pipe(
    toItems(input), // TE.TaskEither<Error, string[]>
    TE.map(items => // TE.TaskEither<E, E.Either<Error, string[]>>
      A.array.traverse(E.either)( // E.Either<Error, string[]>
        items,
        F.flow( // E.Either<Error, string>
          toTitle,
          E.chain(s => E.fromOption(() => Error())(clean(s)))
        )
      )
    )
  );

Codesandbox

这篇关于在fp-ts和函数式编程中管理monad数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆