partial.lenses: how to use asynchronous operations in optics with L.collect?












3















I understand that 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 from the partial.lenses library. Goal is just to get a flattened array of file names.



Problem: instead of using fs.readdirSync I would like to make use of asynchronous, Promise returning versions of the Node's fs API, in my optics.



The following would be the promisified version of the readdir:



const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)


Below is the actual implementation. I would like to know how I can replace the synchronous fs.readdirSync in the readdir function with an asynchronous version.



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 })
)









share|improve this question


















  • 1





    There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

    – toastal
    Nov 18 '18 at 16:20
















3















I understand that 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 from the partial.lenses library. Goal is just to get a flattened array of file names.



Problem: instead of using fs.readdirSync I would like to make use of asynchronous, Promise returning versions of the Node's fs API, in my optics.



The following would be the promisified version of the readdir:



const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)


Below is the actual implementation. I would like to know how I can replace the synchronous fs.readdirSync in the readdir function with an asynchronous version.



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 })
)









share|improve this question


















  • 1





    There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

    – toastal
    Nov 18 '18 at 16:20














3












3








3


2






I understand that 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 from the partial.lenses library. Goal is just to get a flattened array of file names.



Problem: instead of using fs.readdirSync I would like to make use of asynchronous, Promise returning versions of the Node's fs API, in my optics.



The following would be the promisified version of the readdir:



const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)


Below is the actual implementation. I would like to know how I can replace the synchronous fs.readdirSync in the readdir function with an asynchronous version.



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 })
)









share|improve this question














I understand that 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 from the partial.lenses library. Goal is just to get a flattened array of file names.



Problem: instead of using fs.readdirSync I would like to make use of asynchronous, Promise returning versions of the Node's fs API, in my optics.



The following would be the promisified version of the readdir:



const util = require('util')
const fs = require('fs')
const readdirAsync = util.promisify(fs.readdir)


Below is the actual implementation. I would like to know how I can replace the synchronous fs.readdirSync in the readdir function with an asynchronous version.



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 })
)






node.js partial-lenses






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 16 '18 at 7:35









Esko LahtiEsko Lahti

1812




1812








  • 1





    There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

    – toastal
    Nov 18 '18 at 16:20














  • 1





    There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

    – toastal
    Nov 18 '18 at 16:20








1




1





There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

– toastal
Nov 18 '18 at 16:20





There is no need to use Lodash here. You can replace that dependency by switching _.isArray to Array.isArray.

– toastal
Nov 18 '18 at 16:20












1 Answer
1






active

oldest

votes


















4














This is an interesting question in the sense that Partial Lenses can work on
asynchronous problems like this, but the library currently only provides a
little bit of direct support for asynchronous operations out-of-the-box. In the
future the library could certainly be extended to provide more support for
performing asynchronous operations.



Traversals in Partial Lenses build
applicative operations. By
using different applicatives different kinds of operations, like collecting
elements, computing a minimum of elements, or computing a new version of the
data structure, can be performed.



Many operations, like collecting elements or computing minimums, have an
underlying monoid. Any monoid, like array
concatenation



const ConcatArray = {empty: () => , concat: (l, r) => l.concat(r)}


can be converted to an applicative. In Partial Lenses the
L.concat and
L.concatAs
operations do that internally.



So, for collecting elements asynchronously, we could use an asynchronous version
of a concatenating monoid. We can get there by creating a function that
converts any monoid to an asynchronous monoid:



const asyncMonoid = m => ({
empty: async () => m.empty(),
concat: async (l, r) => m.concat(await l, await r)
})


We can now define an asynchronous version of
L.collect as follows:



const collectAsync = L.concatAs(
async x => [x],
asyncMonoid(ConcatArray)
)


One more thing we need for solving this problem is a way to get the result of an
asynchronous operation so that we can zoom into it using optics. For that we
could define a new primitive optic
function that awaits
for the focus before passing it forward in the optic composition:



const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)


Using the above awaitIt optic, we can now define asynchronous traversals over
the files in a file system given a suitable asynchronous readDirectory
function:



const filesUnderEntries = L.lazy(() => [
awaitIt,
L.elems,
L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
])

const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]


We can use the above traversals to examine a directory structure and select
files from under it. We can also further compose operations to read those files
and examine data from those files. For example



collectAsync(
[
filesUnderDirectory,
L.when(R.test(/.my$/)),
L.reread(readFile),
awaitIt
]
)


defines an asynchronous operation that traverses a directory tree and produces
the contents of files with the .my extension under the directory tree.



Here is a playground with full code and examples using faked file system
operations.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53333345%2fpartial-lenses-how-to-use-asynchronous-operations-in-optics-with-l-collect%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4














    This is an interesting question in the sense that Partial Lenses can work on
    asynchronous problems like this, but the library currently only provides a
    little bit of direct support for asynchronous operations out-of-the-box. In the
    future the library could certainly be extended to provide more support for
    performing asynchronous operations.



    Traversals in Partial Lenses build
    applicative operations. By
    using different applicatives different kinds of operations, like collecting
    elements, computing a minimum of elements, or computing a new version of the
    data structure, can be performed.



    Many operations, like collecting elements or computing minimums, have an
    underlying monoid. Any monoid, like array
    concatenation



    const ConcatArray = {empty: () => , concat: (l, r) => l.concat(r)}


    can be converted to an applicative. In Partial Lenses the
    L.concat and
    L.concatAs
    operations do that internally.



    So, for collecting elements asynchronously, we could use an asynchronous version
    of a concatenating monoid. We can get there by creating a function that
    converts any monoid to an asynchronous monoid:



    const asyncMonoid = m => ({
    empty: async () => m.empty(),
    concat: async (l, r) => m.concat(await l, await r)
    })


    We can now define an asynchronous version of
    L.collect as follows:



    const collectAsync = L.concatAs(
    async x => [x],
    asyncMonoid(ConcatArray)
    )


    One more thing we need for solving this problem is a way to get the result of an
    asynchronous operation so that we can zoom into it using optics. For that we
    could define a new primitive optic
    function that awaits
    for the focus before passing it forward in the optic composition:



    const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)


    Using the above awaitIt optic, we can now define asynchronous traversals over
    the files in a file system given a suitable asynchronous readDirectory
    function:



    const filesUnderEntries = L.lazy(() => [
    awaitIt,
    L.elems,
    L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
    ])

    const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]


    We can use the above traversals to examine a directory structure and select
    files from under it. We can also further compose operations to read those files
    and examine data from those files. For example



    collectAsync(
    [
    filesUnderDirectory,
    L.when(R.test(/.my$/)),
    L.reread(readFile),
    awaitIt
    ]
    )


    defines an asynchronous operation that traverses a directory tree and produces
    the contents of files with the .my extension under the directory tree.



    Here is a playground with full code and examples using faked file system
    operations.






    share|improve this answer




























      4














      This is an interesting question in the sense that Partial Lenses can work on
      asynchronous problems like this, but the library currently only provides a
      little bit of direct support for asynchronous operations out-of-the-box. In the
      future the library could certainly be extended to provide more support for
      performing asynchronous operations.



      Traversals in Partial Lenses build
      applicative operations. By
      using different applicatives different kinds of operations, like collecting
      elements, computing a minimum of elements, or computing a new version of the
      data structure, can be performed.



      Many operations, like collecting elements or computing minimums, have an
      underlying monoid. Any monoid, like array
      concatenation



      const ConcatArray = {empty: () => , concat: (l, r) => l.concat(r)}


      can be converted to an applicative. In Partial Lenses the
      L.concat and
      L.concatAs
      operations do that internally.



      So, for collecting elements asynchronously, we could use an asynchronous version
      of a concatenating monoid. We can get there by creating a function that
      converts any monoid to an asynchronous monoid:



      const asyncMonoid = m => ({
      empty: async () => m.empty(),
      concat: async (l, r) => m.concat(await l, await r)
      })


      We can now define an asynchronous version of
      L.collect as follows:



      const collectAsync = L.concatAs(
      async x => [x],
      asyncMonoid(ConcatArray)
      )


      One more thing we need for solving this problem is a way to get the result of an
      asynchronous operation so that we can zoom into it using optics. For that we
      could define a new primitive optic
      function that awaits
      for the focus before passing it forward in the optic composition:



      const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)


      Using the above awaitIt optic, we can now define asynchronous traversals over
      the files in a file system given a suitable asynchronous readDirectory
      function:



      const filesUnderEntries = L.lazy(() => [
      awaitIt,
      L.elems,
      L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
      ])

      const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]


      We can use the above traversals to examine a directory structure and select
      files from under it. We can also further compose operations to read those files
      and examine data from those files. For example



      collectAsync(
      [
      filesUnderDirectory,
      L.when(R.test(/.my$/)),
      L.reread(readFile),
      awaitIt
      ]
      )


      defines an asynchronous operation that traverses a directory tree and produces
      the contents of files with the .my extension under the directory tree.



      Here is a playground with full code and examples using faked file system
      operations.






      share|improve this answer


























        4












        4








        4







        This is an interesting question in the sense that Partial Lenses can work on
        asynchronous problems like this, but the library currently only provides a
        little bit of direct support for asynchronous operations out-of-the-box. In the
        future the library could certainly be extended to provide more support for
        performing asynchronous operations.



        Traversals in Partial Lenses build
        applicative operations. By
        using different applicatives different kinds of operations, like collecting
        elements, computing a minimum of elements, or computing a new version of the
        data structure, can be performed.



        Many operations, like collecting elements or computing minimums, have an
        underlying monoid. Any monoid, like array
        concatenation



        const ConcatArray = {empty: () => , concat: (l, r) => l.concat(r)}


        can be converted to an applicative. In Partial Lenses the
        L.concat and
        L.concatAs
        operations do that internally.



        So, for collecting elements asynchronously, we could use an asynchronous version
        of a concatenating monoid. We can get there by creating a function that
        converts any monoid to an asynchronous monoid:



        const asyncMonoid = m => ({
        empty: async () => m.empty(),
        concat: async (l, r) => m.concat(await l, await r)
        })


        We can now define an asynchronous version of
        L.collect as follows:



        const collectAsync = L.concatAs(
        async x => [x],
        asyncMonoid(ConcatArray)
        )


        One more thing we need for solving this problem is a way to get the result of an
        asynchronous operation so that we can zoom into it using optics. For that we
        could define a new primitive optic
        function that awaits
        for the focus before passing it forward in the optic composition:



        const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)


        Using the above awaitIt optic, we can now define asynchronous traversals over
        the files in a file system given a suitable asynchronous readDirectory
        function:



        const filesUnderEntries = L.lazy(() => [
        awaitIt,
        L.elems,
        L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
        ])

        const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]


        We can use the above traversals to examine a directory structure and select
        files from under it. We can also further compose operations to read those files
        and examine data from those files. For example



        collectAsync(
        [
        filesUnderDirectory,
        L.when(R.test(/.my$/)),
        L.reread(readFile),
        awaitIt
        ]
        )


        defines an asynchronous operation that traverses a directory tree and produces
        the contents of files with the .my extension under the directory tree.



        Here is a playground with full code and examples using faked file system
        operations.






        share|improve this answer













        This is an interesting question in the sense that Partial Lenses can work on
        asynchronous problems like this, but the library currently only provides a
        little bit of direct support for asynchronous operations out-of-the-box. In the
        future the library could certainly be extended to provide more support for
        performing asynchronous operations.



        Traversals in Partial Lenses build
        applicative operations. By
        using different applicatives different kinds of operations, like collecting
        elements, computing a minimum of elements, or computing a new version of the
        data structure, can be performed.



        Many operations, like collecting elements or computing minimums, have an
        underlying monoid. Any monoid, like array
        concatenation



        const ConcatArray = {empty: () => , concat: (l, r) => l.concat(r)}


        can be converted to an applicative. In Partial Lenses the
        L.concat and
        L.concatAs
        operations do that internally.



        So, for collecting elements asynchronously, we could use an asynchronous version
        of a concatenating monoid. We can get there by creating a function that
        converts any monoid to an asynchronous monoid:



        const asyncMonoid = m => ({
        empty: async () => m.empty(),
        concat: async (l, r) => m.concat(await l, await r)
        })


        We can now define an asynchronous version of
        L.collect as follows:



        const collectAsync = L.concatAs(
        async x => [x],
        asyncMonoid(ConcatArray)
        )


        One more thing we need for solving this problem is a way to get the result of an
        asynchronous operation so that we can zoom into it using optics. For that we
        could define a new primitive optic
        function that awaits
        for the focus before passing it forward in the optic composition:



        const awaitIt = async (x, i, F, xi2yF) => xi2yF(await x, i)


        Using the above awaitIt optic, we can now define asynchronous traversals over
        the files in a file system given a suitable asynchronous readDirectory
        function:



        const filesUnderEntries = L.lazy(() => [
        awaitIt,
        L.elems,
        L.ifElse(L.get('isDir'), ['path', filesUnderDirectory], 'path')
        ])

        const filesUnderDirectory = [L.reread(readDirectory), filesUnderEntries]


        We can use the above traversals to examine a directory structure and select
        files from under it. We can also further compose operations to read those files
        and examine data from those files. For example



        collectAsync(
        [
        filesUnderDirectory,
        L.when(R.test(/.my$/)),
        L.reread(readFile),
        awaitIt
        ]
        )


        defines an asynchronous operation that traverses a directory tree and produces
        the contents of files with the .my extension under the directory tree.



        Here is a playground with full code and examples using faked file system
        operations.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 16 '18 at 7:58









        polytypicpolytypic

        1913




        1913
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53333345%2fpartial-lenses-how-to-use-asynchronous-operations-in-optics-with-l-collect%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            List item for chat from Array inside array React Native

            Thiostrepton

            Caerphilly