代码之家  ›  专栏  ›  技术社区  ›  Matías Fidemraizer

函数式编程中连接等线程资源的处理方法

  •  3
  • Matías Fidemraizer  · 技术社区  · 6 年前

    假设您需要连接到数据库。

    所以,你给 DbConnection 作为某个具有如下类型的假设函数的最后一个参数: doDbStuff :: Int -> DbConnection -> Int

    也许还有其他的功能也依赖于 数据库连接类 交易

    因为一个人可能想管理 数据库连接类 使用 水塘 从池和到池的实例。

    现在,这些函数是一个长函数组合的一部分,某些决策可能涉及不需要 . 也就是说,有可能 可能从池中获取,并且可能被另一个请求使用,这可能会产生瓶颈。

    还有一种选择,就是不注射 但是一个高阶函数 withConnection :: (DbConnection -> a) -> a 数据库连接类 ,使用它和整个 withConnection

    所以。。。

    JavaScript中的伪代码:

    const connectionString = '[whatever]'
    const env = { connection: acquire (connectionString) }
    
    const output = composition (arg0) (argN) (env)
    // then, release the connection
    
    // f :: a -> b -> { connection: DbConnection }
    const f = x => y => ({ connection }) => 
        doDbStuff (x + y) (connection)
    

    方法2

    const withConnection = f => [stuff to acquire the connection, and aftewards, release it]
    const env = { withConnection }
    
    const output = composition (arg0) (argN) (env)
    
    // type FnConnection DbConnection c = c -> a
    // f :: a -> a -> { connection: FnConnection }
    const f = x => y => ({ withConnection }) => 
        withConnection (doDbStuff (x + y))
    
    0 回复  |  直到 6 年前
        1
  •  1
  •   Alfred Young    5 年前

    有一个工具可以解决这种情况,你的解决方案非常接近!reader adt允许您在访问某个环境的上下文中编写函数。以下是我最喜欢的实现: https://github.com/monet/monet.js/blob/master/docs/READER.md

    不幸的是,这种模式可能需要将大量代码包装在reader类型中,但是您已经引入了withConnection包装器,这将导致几乎相同数量的额外代码。

    const { Reader } = require('monet');
    
    const findById = (id) => Reader(({ db }) => db.find({ id }));
    const insertDoc = (doc) => Reader(({ db }) => db.insert(doc));
    const copyWithDefaults = (doc) => ({
        ...doc,
        name: 'default name',
    });
    
    const app =
        findById('123')
            .map(copyWithDefaults)
            .chain(insertDoc)
    
    app.run({ db: aquire(connectionString) })