在clojure中,对数据执行一系列测试函数的惯用方法是什么,每个函数都有副作用?

在clojure中,对数据执行一系列测试函数的惯用方法是什么,每个函数都有副作用?,clojure,Clojure,假设我们要对电子邮件地址和与电子邮件相关的数据进行一系列检查: 检查电子邮件是否为零?如果nil返回{:msg emial为nil} 检查电子邮件是否有帐户,即对电子邮件帐户进行数据库查找。如果account为nil,则返回{:msg no account} 检查帐户是否已过期。如果帐户未处于过期状态,则返回{:msg expired} 。。等等 Currrently, I have coded this as nested if-let statements: (if-let

假设我们要对电子邮件地址和与电子邮件相关的数据进行一系列检查:

检查电子邮件是否为零?如果nil返回{:msg emial为nil}

检查电子邮件是否有帐户,即对电子邮件帐户进行数据库查找。如果account为nil,则返回{:msg no account}

检查帐户是否已过期。如果帐户未处于过期状态,则返回{:msg expired}

。。等等

Currrently, I have coded this as nested if-let statements:
         (if-let [email (if (nil? email) nil email)]
               (if-let [acct (load-act email)]
                   (if-let [goodacct (if (expired? acct) nil acct)]    
                ....        
))

有没有更好的方法或更惯用的方法来写这篇文章?

有几种方法可以考虑这一点:

1将电子邮件上的“无”复选框移到链的更高位置。那么你的功能就可以了

(let [acct (load-act email)]
  (cond (nil? acct)     "no account"
        (expired? acct) "account expired"
        :else           acct))
并非所有的测试都需要保留结果。if let可以简化为

(if (nil? email)
  "email is nil"
  (if-let [acct (load-act email)]
    (if (expired? acct)
      "account expired"
      acct)
    "no account"))
旁注——clojure关于虚假性的概念是零和虚假的。你用的是零?检查哪一个只检查零,如果让哪一个也检查假。有一些只做零检查

3允许在其cond构造内进行绑定:

(b/cond
  (nil? email) "email is nil"
  :let [acct (load-act email)]
  (nil? acct) "no account"
  (expired? acct) "account expired"
  :else acct)

有几种方法可以考虑这一点:

1将电子邮件上的“无”复选框移到链的更高位置。那么你的功能就可以了

(let [acct (load-act email)]
  (cond (nil? acct)     "no account"
        (expired? acct) "account expired"
        :else           acct))
并非所有的测试都需要保留结果。if let可以简化为

(if (nil? email)
  "email is nil"
  (if-let [acct (load-act email)]
    (if (expired? acct)
      "account expired"
      acct)
    "no account"))
旁注——clojure关于虚假性的概念是零和虚假的。你用的是零?检查哪一个只检查零,如果让哪一个也检查假。有一些只做零检查

3允许在其cond构造内进行绑定:

(b/cond
  (nil? email) "email is nil"
  :let [acct (load-act email)]
  (nil? acct) "no account"
  (expired? acct) "account expired"
  :else acct)

与@xificurC的上一个版本相同。 但是为什么不使用普通语法呢?不需要不必要的依赖关系。 这不是更多的打字吗

(cond (nil? email) {:msg "email is nil"}
      :else (let [acct (load-act email)]
              (cond (nil? acct) {:msg "no account"}
                    (expired? acct) {:msg "expired account"}
                    :else acct)))
当然,我们可以讨论第一个条件是否应该是if。 但我喜欢cond,因为它在左右手水平放置因果关系。
逻辑像瀑布一样向下流动,但一旦满足条件就会退出。

与@xificurC的上一个版本相同。 但是为什么不使用普通语法呢?不需要不必要的依赖关系。 这不是更多的打字吗

(cond (nil? email) {:msg "email is nil"}
      :else (let [acct (load-act email)]
              (cond (nil? acct) {:msg "no account"}
                    (expired? acct) {:msg "expired account"}
                    :else acct)))
当然,我们可以讨论第一个条件是否应该是if。 但我喜欢cond,因为它在左右手水平放置因果关系。
逻辑像瀑布一样向下流动,但一旦满足条件就会退出。

还有另一种方法:将用户帐户建模为普通映射,并定义一些基本的验证函数。如果这只是您感兴趣的第一个错误,那么您可以跨同一个用户帐户数据映射不同函数的应用程序,并选择第一个错误

您可以增强此功能,以收集向量中的所有错误,或增强地图,例如使用reduce,以便验证管道上进一步的步骤可以重复使用从先前阶段的副作用中获得的数据,例如,如果先前的步骤转到db,可能会将更多的键关联到映射中,以便以后的验证可以重复使用相同的数据,而无需额外的查询。您需要更改验证函数以获取映射并返回一对[Update map error]

一个快速而肮脏的例子:

defn有效电子邮件[{:keys[email]}] 非电子邮件时,电子邮件为零 defn有效帐户[{:keys[account]}] 不算帐不算帐 defn过期帐户[{:keys[account]}] 何时:过期帐户帐户已过期 def验证[有效电子邮件有效帐户过期帐户] defn验证程序[用户数据] 当让[错误某些身份映射%用户数据验证] {:msg错误} ;; 验证器{} ;; => {:msg电子邮件为零} ;; 验证程序{:电子邮件a@b.com} ;; => {:msg无帐户} ;; 验证程序{:电子邮件a@b.com:帐户{:expired true} ;; => {:msg帐户已过期} ;; 验证程序{:电子邮件a@b.com:帐户{:过期错误} ;; => 无nil表示没有验证错误
还有另一种方法:将用户帐户建模为普通映射,并定义一些基本的验证函数。如果这只是您感兴趣的第一个错误,那么您可以跨同一个用户帐户数据映射不同函数的应用程序,并选择第一个错误

您可以增强此功能,以收集向量中的所有错误,或增强地图,例如使用reduce,以便验证管道上进一步的步骤可以重复使用从先前阶段的副作用中获得的数据,例如,如果先前的步骤转到db,可能会将更多的键关联到映射中,以便以后的验证可以重复使用相同的数据,而无需额外的查询。您需要更改验证函数以获取映射并返回一对[Update map error]

一个快速而肮脏的例子:

defn有效电子邮件[{:keys[email]}] 非电子邮件时,电子邮件为零 defn有效帐户[{:keys[account]}] 不算帐不算帐 defn过期帐户[{:keys[account]}] 何时:过期帐户帐户已过期 def验证[有效电子邮件有效帐户过期帐户] defn验证程序[用户数据] 当让[error]某些标识映射%us时 er数据验证] {:msg错误} ;; 验证器{} ;; => {:msg电子邮件为零} ;; 验证程序{:电子邮件a@b.com} ;; => {:msg无帐户} ;; 验证程序{:电子邮件a@b.com:帐户{:expired true} ;; => {:msg帐户已过期} ;; 验证程序{:电子邮件a@b.com:帐户{:过期错误} ;; => 无nil表示没有验证错误
只需提一下:一个用来解决这类问题的术语是面向铁路的规划,在FP圈中经常使用的是两者之一。为此,有几家图书馆。值得一提的是:仅此而已:用于解决这类问题的术语是面向铁路的规划,而FP界经常使用的术语是两者之一。为此,有几家图书馆。值得一提的是:这是一个很好的抽象,很容易扩展!这段代码可读性强,易于测试,易于推理。这是一个很好的抽象,很容易扩展!该代码可读性强,易于测试,易于推理。