V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
witcat
V2EX  ›  JavaScript

在学习函数式编程, Ramda 的一些疑问

  •  
  •   witcat · 2022-12-05 12:26:32 +08:00 · 2099 次点击
    这是一个创建于 501 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本人菜鸟...之前没特意研究过函数式编程
    最近再做一个三消游戏,写了一点 Ramda ,我发现一个问题
    下面这段大概意思是根据 row.length 判断当前这个格子需不需要填充砖块,根据结果返回砖块值或 null
    最后 prepend 到 map 里

    compose(
    	prepend,
        ifElse(identity<boolean>, brickSample, always(null)),
        shouldFill
    )(row.length)(row),
    

    问题是我写了很多经常出现(arg)(map)这样的代码
    直觉这样写不对,因为我看别人的代码没有这么写过,也许根据入参获取砖块值是一个流程,prepend 到地图里是另外一个流程
    就又改成这样了:

    prepend(
        compose(
            ifElse(identity<boolean>, brickSample, always(null)),
            shouldFill
        )(row.length),
        row
    ),
    

    但是还是感觉很乱,有更好看的写法吗?

    9 条回复    2022-12-05 17:50:07 +08:00
    witcat
        1
    witcat  
    OP
       2022-12-05 13:07:19 +08:00
    突然想起来可以用 copilot ,去充了一个,对学习很有帮助。
    贴两个 copilot 写的 😂
    ```
    ifElse(
    shouldFill,
    compose(prepend, brickSample),
    compose(prepend, always(null))
    )(row.length)(row),
    ```
    ```
    prepend(
    ifElse(shouldFill, brickSample, always(null))(row.length),
    row
    ),
    ```
    lmshl
        2
    lmshl  
       2022-12-05 13:35:10 +08:00   ❤️ 1
    楼主的用法真的是辣眼睛。

    关于 JS 函数式编程,前两天我写了个知乎回答,贴过来 https://www.zhihu.com/question/570165038/answer/2784350974

    Leviathann
        3
    Leviathann  
       2022-12-05 13:44:25 +08:00
    point free 就是要把代码写成文章
    如果无法从语义上(也就是函数名)表达代码在做什么那就是没写好,或者说这段代码不适合 point free
    wanacry
        4
    wanacry  
       2022-12-05 13:46:44 +08:00
    关于 Ramda 的写法,它提供了一些函数组合的工具函数,例如 compose 、pipe 等,可以用来把多个函数组合在一起,并且从右往左依次执行。

    对于上面的代码,可以把两个部分分别写成两个函数,然后用 compose 组合在一起,代码如下:

    const getBrick = compose(
    ifElse(identity<boolean>, brickSample, always(null)),
    shouldFill
    )

    const prependBrick = (map) => (row) => prepend(getBrick(row.length)(row), map)

    prependBrick(map)(row)

    这样就可以很清晰地看出来,前面的部分是根据 row.length 获取砖块值,后面的部分是 prepend 到地图里。

    当然,这个写法并不是必须的,你可以按照自己的喜好写,只要保证代码可读性即可。
    witcat
        5
    witcat  
    OP
       2022-12-05 13:48:40 +08:00
    @lmshl 看不懂你写的文 同样的功能你能不能改一个 让我看看不辣的函数式 js 是什么样的
    lmshl
        6
    lmshl  
       2022-12-05 13:54:46 +08:00
    不辣的
    ```javascript
    if (!shouldFill(row.length)) return row

    const arr = brickSample()
    return prepend(row, arr)
    ```
    novolunt
        7
    novolunt  
       2022-12-05 14:22:39 +08:00
    // Define named functions for each part of the code.
    function shouldFill(length: number) {
    // Determine whether the current cell should be filled with a brick.
    return length > 0;
    }

    function brickSample(filled: boolean) {
    // If the cell should be filled, return the value of a brick.
    // Otherwise, return null.
    return filled ? BRICK_VALUE : null;
    }

    function prependBrick(brick: any, row: any[]) {
    // Prepend the given brick to the given row.
    return [brick, ...row];
    }

    // Use the named functions to create a new, composed function.
    const fillRow = compose(
    prependBrick,
    brickSample,
    shouldFill
    );

    // Use the composed function to fill the cells in a row.
    const filledRow = fillRow(row.length, row);
    cnhongwei
        8
    cnhongwei  
       2022-12-05 14:54:07 +08:00
    开眼了,感觉 Ramda 真的是函数式。但程序变得好神奇。
    看了之后,还是坚定的自己的习惯,保持数据不可变,用好 map flatmap filter reduce 就可以好好的函数式编程了。
    libook
        9
    libook  
       2022-12-05 17:50:07 +08:00
    做了 10 年 JS 全栈开发,表示两段看起来都很难读懂。

    一般 JS 开发者的思维都是 foo() 或 foo=() 这种形式,即函数名后紧跟参数表的形式,所以看到 ()()() 这种形式就需要转换思维,先在脑内模拟运行前面的部分才能知道返回了什么函数来使用后面的参数表,在代码特别长的时候,单拎出来中间一部分可能无法确定是在执行什么函数,可能降低了代码阅读理解的效率。工业上来讲,个人认为 a().b().c() 这样链式调用的形式可能更明确。

    通常,函数调用和逻辑判断流程有明显的语法格式差异,可以帮助阅读者快速切换这两种语境,但当流程控制也被封装成函数的时候,就需要人去了解函数内部的流程特征,个人认为不如直接在相关代码附近喂给阅读者要方便,在各个函数声明的区域跳来跳去也比较打断思路。

    或许题主只想做一个使用 JS 实现的完全函数式编程案例,尽管这不是工业上最普遍的风格;这样的话题主就不要纠结好看不好看了,符合教材范式和核心目标就好吧。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2783 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 11:45 · PVG 19:45 · LAX 04:45 · JFK 07:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.