partial.lenses: 如何在 L.collect 的光学中使用异步操作?
partial.lenses: how to use asynchronous operations in optics with L.collect?
我从 partial.lenses 图书馆了解到 partial.lenses isn't necessarily the best solution to the following problem and that's besides the point in this question. I was trying to list files from a directory using L.collect。目标只是获得一个扁平化的文件名数组。
问题:我不想使用 fs.readdirSync,而是想在我的光学器件中使用异步的、Promise 返回版本的 Node 的 fs API。
以下是 readdir 的承诺版本:
const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)
下面是实际的实现。我想知道如何用异步版本替换 readdir
函数中的同步 fs.readdirSync
。
const L = require("partial.lenses")
const fs = require("fs")
const path = require("path")
const _ = require("lodash")
const basePath = path.basename(`${__dirname}/..`)
const isDirectory = dirent => {
return dirent instanceof fs.Dirent ? dirent.isDirectory() : false
}
const readDir = path => () => {
return fs.readdirSync(path, { withFileTypes: true })
}
const leafs = nodePath => {
return L.cond(
[
_.isArray,
L.lazy(() => [
L.elems,
L.choose(({ name }) => leafs(path.join(nodePath, name)))
])
],
[
isDirectory,
L.lazy(() => [
readDir(nodePath),
L.elems,
L.choose(({ name }) => leafs(path.join(nodePath, name)))
])
],
[L.identity]
)
}
const listFiles = async () =>
L.collect(
leafs(basePath),
fs.readdirSync(basePath, { withFileTypes: true })
)
这是一个有趣的问题,因为局部透镜可以用于
像这样的异步问题,但是库目前只提供了一个
开箱即用的对异步操作的一点点直接支持。在里面
未来图书馆肯定可以扩展以提供更多支持
执行异步操作。
部分镜头构建中的遍历
applicative 操作。经过
使用不同的应用程序进行不同类型的操作,例如收集
元素,计算最少的元素,或计算新版本的
数据结构,可以执行。
许多操作,例如收集元素或计算最小值,都有一个
底层 monoid。任何幺半群,如数组
串联
const ConcatArray = {empty: () => [], concat: (l, r) => l.concat(r)}
可以转换为应用程序。在部分镜头中
L.concat
和
L.concatAs
操作在内部执行此操作。
所以,为了异步收集元素,我们可以使用异步版本
串联的幺半群。我们可以通过创建一个函数来实现
将任何幺半群转换为异步幺半群:
const asyncMonoid = m => ({
empty: async () => m.empty(),
concat: async (l, r) => m.concat(await l, await r)
})
我们现在可以定义异步版本
L.collect
如下:
const collectAsync = L.concatAs(
async x => [x],
asyncMonoid(ConcatArray)
)
我们还需要解决这个问题的一件事是获得
异步操作,以便我们可以使用光学放大它。为此我们
可以定义一个新的 原始光学
等待的函数
在光学组合中向前传递焦点之前的焦点:
const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)
使用上面的 awaitIt
optical,我们现在可以定义异步遍历
给定合适的异步 readDirectory
的文件系统中的文件
功能:
const filesUnderEntries = L.lazy(() => [
awaitIt,
L.elems,
L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
])
const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]
我们可以使用上面的遍历来检查目录结构和select
它下面的文件。我们还可以进一步组合操作来读取这些文件
并检查这些文件中的数据。例如
collectAsync(
[
filesUnderDirectory,
L.when(R.test(/\.my$/)),
L.reread(readFile),
awaitIt
]
)
定义一个遍历目录树并生成的异步操作
目录树下扩展名为 .my
的文件的内容。
我从 partial.lenses 图书馆了解到 partial.lenses isn't necessarily the best solution to the following problem and that's besides the point in this question. I was trying to list files from a directory using L.collect。目标只是获得一个扁平化的文件名数组。
问题:我不想使用 fs.readdirSync,而是想在我的光学器件中使用异步的、Promise 返回版本的 Node 的 fs API。
以下是 readdir 的承诺版本:
const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)
下面是实际的实现。我想知道如何用异步版本替换 readdir
函数中的同步 fs.readdirSync
。
const L = require("partial.lenses")
const fs = require("fs")
const path = require("path")
const _ = require("lodash")
const basePath = path.basename(`${__dirname}/..`)
const isDirectory = dirent => {
return dirent instanceof fs.Dirent ? dirent.isDirectory() : false
}
const readDir = path => () => {
return fs.readdirSync(path, { withFileTypes: true })
}
const leafs = nodePath => {
return L.cond(
[
_.isArray,
L.lazy(() => [
L.elems,
L.choose(({ name }) => leafs(path.join(nodePath, name)))
])
],
[
isDirectory,
L.lazy(() => [
readDir(nodePath),
L.elems,
L.choose(({ name }) => leafs(path.join(nodePath, name)))
])
],
[L.identity]
)
}
const listFiles = async () =>
L.collect(
leafs(basePath),
fs.readdirSync(basePath, { withFileTypes: true })
)
这是一个有趣的问题,因为局部透镜可以用于 像这样的异步问题,但是库目前只提供了一个 开箱即用的对异步操作的一点点直接支持。在里面 未来图书馆肯定可以扩展以提供更多支持 执行异步操作。
部分镜头构建中的遍历 applicative 操作。经过 使用不同的应用程序进行不同类型的操作,例如收集 元素,计算最少的元素,或计算新版本的 数据结构,可以执行。
许多操作,例如收集元素或计算最小值,都有一个 底层 monoid。任何幺半群,如数组 串联
const ConcatArray = {empty: () => [], concat: (l, r) => l.concat(r)}
可以转换为应用程序。在部分镜头中
L.concat
和
L.concatAs
操作在内部执行此操作。
所以,为了异步收集元素,我们可以使用异步版本 串联的幺半群。我们可以通过创建一个函数来实现 将任何幺半群转换为异步幺半群:
const asyncMonoid = m => ({
empty: async () => m.empty(),
concat: async (l, r) => m.concat(await l, await r)
})
我们现在可以定义异步版本
L.collect
如下:
const collectAsync = L.concatAs(
async x => [x],
asyncMonoid(ConcatArray)
)
我们还需要解决这个问题的一件事是获得 异步操作,以便我们可以使用光学放大它。为此我们 可以定义一个新的 原始光学 等待的函数 在光学组合中向前传递焦点之前的焦点:
const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)
使用上面的 awaitIt
optical,我们现在可以定义异步遍历
给定合适的异步 readDirectory
的文件系统中的文件
功能:
const filesUnderEntries = L.lazy(() => [
awaitIt,
L.elems,
L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
])
const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]
我们可以使用上面的遍历来检查目录结构和select 它下面的文件。我们还可以进一步组合操作来读取这些文件 并检查这些文件中的数据。例如
collectAsync(
[
filesUnderDirectory,
L.when(R.test(/\.my$/)),
L.reread(readFile),
awaitIt
]
)
定义一个遍历目录树并生成的异步操作
目录树下扩展名为 .my
的文件的内容。