Repository: gcanti/fp-ts
Pull request #832 (2019-04-15 15:13:36)

New Feature: add NonEmptyArray2v.modifyAt


Patch:
diff --git a/docs/faq.md b/docs/faq.md
new file mode 100644
index 00000000..a14f6a26
--- /dev/null
+++ b/docs/faq.md
@@ -0,0 +1,50 @@
+---
+title: FAQ
+permalink: /faq/
+nav_order: 6
+has_children: false
+has_toc: false
+---
+
+# Frequently Asked Questions
+{: .no_toc }
+
+## Table of contents
+{: .no_toc .text-delta }
+
+1. TOC
+{:toc}
+
+## Data Types
+
+### How can I handle errors with Tasks?
+
+Not every async computation necessarily needs error handling, which is why [Task](../modules/Task.ts) is simply defined as `Task<A>`. If you do need to handle errors, you can use [TaskEither](../modules/TaskEither.ts) or variations of `Task` like `Task<Option<A>>` or `Task<Validation<L, A>>`.
+
+## Where do I find …?
+
+### Where do I find the Maybe data type?
+
+`fp-ts` provides the [Option](../modules/Option.ts) data type, which is conceptually similar to the `Maybe` data type.
+
+### Where do I find the liftA2, liftA3, … functions?
+
+Use [sequenceT](../modules/Apply.ts.html#sequencet-function) and [sequenceS](../modules/Apply.ts.html#sequences-function) instead.
+
+## Techniques
+
+### Is it possible to serialize and deserialize an fp-ts type?
+
+Yes, you can create an [io-ts](https://github.com/gcanti/io-ts) encoder/decoder for sending/receiving a data type like [Option](../modules/Option.ts) or [Either](../modules/Either.ts) over a network or exchange data with a web worker. Check out the functions `createOptionFromNullable` and `createEitherFromJSON` from [io-ts-types](https://github.com/gcanti/io-ts-types) for this use-case.
+
+Note that it is not possible to serialize data types that contain functions (like [IO](../modules/IO.ts) or [Task](../modules/Task.ts)).
+
+### Is it possible to use tagless final with fp-ts?
+
+Yes, read [Functional Design: Tagless Final](https://dev.to/gcanti/functional-design-tagless-final-332k) for an introduction. Also have a look at these code examples: [mtl.ts](https://github.com/gcanti/fp-ts/blob/master/tutorials/mtl.ts), [optimizing tagless final](https://gist.github.com/gcanti/85bb38c5cf2cd6fb5a1decf7c04624c2), and [fp-ts-to-the-max-II](https://gist.github.com/gcanti/453e5419fbcabe078d933ab21f0df8bf).
+
+## Miscellaneous
+
+### Does fp-ts provide Flow type definitions?
+
+No, `fp-ts` does not provide official [Flow](https://flow.org/) type definitions.
diff --git a/docs/introduction/core-concepts.md b/docs/introduction/core-concepts.md
index d4bbb55e..94d822e5 100644
--- a/docs/introduction/core-concepts.md
+++ b/docs/introduction/core-concepts.md
@@ -29,9 +29,9 @@ Many functions in `fp-ts` use [ad hoc polymorphism](https://en.wikipedia.org/wik
 ```ts
 import { option, apply } from 'fp-ts'
 
-// liftA2 is an ad hoc polymorphic function and requires an Option instance.
+// sequenceS is an ad hoc polymorphic function and requires an Option instance.
 // This is what option.option provides.
-const liftA2Option = apply.liftA2(option.option)
+const sequenceSOption = apply.sequenceS(option.option)
 ```
 
 Here's a small list of some commonly used data types, you can find more in the [API reference](../modules/).
diff --git a/docs/recipes/async.md b/docs/recipes/async.md
index 3f99b51c..090aa890 100644
--- a/docs/recipes/async.md
+++ b/docs/recipes/async.md
@@ -62,6 +62,28 @@ array
   .then(console.log) // [ 1, 2 ]
 ```
 
+## Run a list of tasks in sequence
+
+If you need to run a list of `Task`s in sequence, i.e. you have to wait for one `Task` to finish before you run the second `Task`, you can use the `taskSeq` instance.
+
+```ts
+import { array } from 'fp-ts/lib/Array'
+import { delay, task, taskSeq } from 'fp-ts/lib/Task'
+const log = <A>(x: A) => { console.log(x); return x }
+
+const tasks = [delay(200, 'first').map(log), delay(100, 'second').map(log)]
+
+// Parallel: logs 'second' then 'first'
+array
+  .sequence(task)(tasks)
+  .run()
+
+// Sequential: logs 'first' then 'second'
+array
+  .sequence(taskSeq)(tasks)
+  .run()
+```
+
 ## Work with a list of dependent tasks
 
 If you need the result of on task before you can continue with the next, you can `chain` the tasks like so:
@@ -75,3 +97,27 @@ task.of(2)
   .run()
   .then(console.log) // 10
 ```
+
+## Traverse: map and sequence
+
+If you have a list of items that you need to `map` over before running them in `sequence`, you can use `traverse`, which is a shortcut for doing both operations in one step.
+
+```ts
+import { array } from 'fp-ts/lib/Array'
+import { task, Task } from 'fp-ts/lib/Task'
+import { access, constants } from 'fs'
+
+const checkPathExists = (path: string) =>
+  new Task(() =>
+    new Promise(resolve => {
+      access(path, constants.F_OK, err => resolve({ path, exists: !err }))
+    })
+  )
+
+const items = ['/bin', '/no/real/path']
+
+array
+  .traverse(task)(items, checkPathExists)
+  .run()
+  .then(console.log) // [ { path: '/bin', exists: true }, { path: '/no/real/path', exists: false } ]
+```
diff --git a/src/NonEmptyArray2v.ts b/src/NonEmptyArray2v.ts
index 763d30b2..79a023fb 100644
--- a/src/NonEmptyArray2v.ts
+++ b/src/NonEmptyArray2v.ts
@@ -258,6 +258,13 @@ export function updateAt<A>(i: number, a: A, nea: NonEmptyArray<A>): Option<NonE
   return A.updateAt(i, a, nea) as any
 }
 
+/**
+ * @since 1.17.0
+ */
+export function modifyAt<A>(nea: NonEmptyArray<A>, i: number, f: (a: A) => A): Option<NonEmptyArray<A>> {
+  return A.modifyAt(nea, i, f) as any
+}
+
 /**
  * @since 1.15.0
  */


Test patch:
diff --git a/test/NonEmptyArray2v.ts b/test/NonEmptyArray2v.ts
index 1eb1bbbe..3af766d0 100644
--- a/test/NonEmptyArray2v.ts
+++ b/test/NonEmptyArray2v.ts
@@ -25,7 +25,8 @@ import {
   filterWithIndex,
   fromNonEmptyArray,
   cons,
-  snoc
+  snoc,
+  modifyAt
 } from '../src/NonEmptyArray2v'
 import { none, option, some, isSome } from '../src/Option'
 import { ordNumber } from '../src/Ord'
@@ -304,6 +305,12 @@ describe.only('NonEmptyArray2v', () => {
     }
   })
 
+  it('modifyAt', () => {
+    const double = (n: number): number => n * 2
+    assert.deepStrictEqual(modifyAt(make<number>(1, []), 1, double), none)
+    assert.deepStrictEqual(modifyAt(make<number>(1, [2]), 1, double), some(make(1, [4])))
+  })
+
   it('filter', () => {
     const make2 = (x: number) => ({ x })
     const a1 = make2(1)