首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >隐式调用函数的正确版本

隐式调用函数的正确版本
EN

Stack Overflow用户
提问于 2017-02-21 21:14:49
回答 1查看 77关注 0票数 2

我有一个应用程序,其中我有一个函数可以在一些不同的上下文中调用,我希望它调用的一些函数在这些不同的上下文中以不同的方式运行。因此,举个例子,我可能有一些代码,这些代码的功能如下

代码语言:javascript
复制
(defn foo [a context]
  (-> a
      inc
      (#(bar % context))))

(defn bar [a context]
  (cond (= context 1) (* a 2)
        (= context 2) (/ a 2)))

尽管有很多不同的函数,比如bar,但是这些函数都隐藏在自己不关心“上下文”的其他函数中。

因为它们隐藏在一堆其他函数中(因为我为一个上下文编写了这段代码,现在正在添加其他函数),修改所有这些函数以将一个标志传递给所有相关的' bar 's是一个麻烦。我也不太喜欢它作为解决方案。理想情况下,我希望在每个上下文中隐式地使用bar函数的正确版本。

协议也许能解决这个问题。但是,我认为用协议重写我的函数将是一个巨大的麻烦,因为(在我的实际函数中)一些'bar‘函数既使用上下文,又将其传递给使用它的其他函数。因此,我想我必须复制一些代码(或者有不同的协议传递标志)。

我想出的解决方案是为foo创建一个名称空间,然后为每个上下文创建一个单独的名称空间。然后,在每个上下文的名称空间中,我定义了一个单独的名称空间。我更改foo,以便它调用驻留在调用命名空间中的bar函数的版本。这就是:

代码语言:javascript
复制
(ns main)

(defn foo [a]
  (-> inc
      ('bar (ns-map *ns*))))

(ns context-1
  (use main))

(defn bar [a]
  (* a 2))

(ns context-2
  (use main))

(defn bar [a]
  (/ a 2))

然后,当我从上下文-1命名空间调用foo时,它按预期工作。上下文-2命名空间也是如此。

这基本上是可行的,只是因为我想从不同的名称空间调用上下文1 foo和上下文2 foo,所以我需要为我为foo函数调用进入名称空间的每个名称空间编写一个包装器,然后切换回我开始使用的名称空间。所以,在上下文中-1 ns,我写了这样的东西:

代码语言:javascript
复制
(defn context-1-foo [a]
  (let [base-ns *ns*]
    (in-ns 'context-1)
    (let [result (foo a)]
      (in-ns (ns-name base-ns))
      result)))

这是可行的,而且它不需要太多的改变,但我认为它一定是非惯用的。它似乎也可能是一个邀请,有奇怪的bug。

做这件事的惯用方法是什么?类似地,是否有一种方法可以对代码进行很少的更改?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-21 21:42:21

更新:

抱歉,在重新阅读了这个问题之后,我发现这并不能解决你对上下文的要求。查看动态绑定可能会有更好的运气,您可以创建一个宏,如下所示:

代码语言:javascript
复制
(with-context 1
  (bar 4))
;; => 8

(with-context 2
  (bar 4))
;; => 2

原始答案

处理此场景的惯用方法是使用Clojure的多方法。如果要调用的方法取决于上下文中的内容,那么多方法将允许您分派匹配特定上下文的方法,这是未来的证明,因为您可以通过简单地指定匹配的上下文来添加更多的方法。

以你为例:

代码语言:javascript
复制
; you could define the context object like:
{:method :bar-1}
; or
{:method :bar-2}

;; Create multimethod that accepts the 2 params 
;; and dispatches on :method in context
(defmulti bar (fn [a context] (:method context)))

;; Method that dispatches when context is {:method :bar-1}
(defmethod bar :bar-1 [a context]
 (* a 2))

;; Method that dispatches when context is {:method :bar-2}
(defmethod bar :bar-2 [a context]
  (/ a 2))

;; Method that dispatches when context is {:method :bar-3}
(defmethod bar :bar-3 [a context]
  ; Some third implementation
  )

然后,只需使用正确的上下文对象调用bar

代码语言:javascript
复制
(bar 4 {:method :bar-1})
;; => 8

(bar 4 {:method :bar-2})
;; => 2

(bar 4 {:method :bar-3})
;; => nil

如上文所示,任何以后的bar实现都可以通过简单的defmethod添加。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42378115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档