【问题标题】:Pass multiple parameters function from other function with Clojure and readability issues从具有 Clojure 和可读性问题的其他函数传递多个参数函数
【发布时间】:2013-10-25 02:39:50
【问题描述】:

我正在尝试使用 SICP 学习函数式编程。我想使用 Clojure。

Clojure 是 Lisp 的一种方言,但我对 Lisp 非常陌生。这段代码 sn -p 不干净且不可读。如何用 Lisp 方言编写更高效的代码?

以及如何从其他函数传递多个参数函数?

(defn greater [x y z]
  (if (and (>= x y) (>= x z)) 
    (if (>= y z)
      [x,y]
      [x,z]) 
    (if (and (>= y x) (>= y z)) 
      (if (>= x z)
        [y,x]
        [y,z]) 
      (if (and (>= z x) (>= z y)) 
        (if (>= y x)
          [z,y]
          [z,x])))))

(defn sum-of-squares [x y]
    (+ (* x x) (* y y)))

(defn -main
  [& args]
  (def greats (greater 2 3 4))
  (def sum (sum-of-squares greats)))

【问题讨论】:

    标签: clojure functional-programming lisp sicp


    【解决方案1】:

    您问了两个问题,我将尝试以相反的顺序回答。

    应用集合作为参数

    要将集合用作函数参数,其中每个项目都是函数的位置参数,您可以使用 apply 函数。

    (apply sum-of-squares greats) ;; => 25
    


    可读性

    至于更普遍的可读性问题:

    您可以通过概括问题来获得可读性。从您的代码示例中,看起来问题在于对集合中的两个最大数字执行平方和。因此,sort 按降序排列集合并取前两项在视觉上会更干净。

    (defn greater [& numbers]
      (take 2 (sort > numbers)))
    
    (defn sum-of-squares [x y]
      (+ (* x x) (* y y)))
    

    然后您可以使用apply 将它们传递给您的sum-of-squares 函数。

    (apply sum-of-squares (greater 2 3 4)) ;; => 25
    

    记住:排序功能不是惰性的。所以,它会实现并排序你给它的整个集合。在某些情况下,这可能会对性能产生影响。但是,在这种情况下,这不是问题。


    更进一步

    您可以通过将xy 这两个参数切换到一个集合来进一步概括您的sum-of-squares 函数以处理多个参数。

    (defn sum-of-squares [& xs]
      (reduce + (map #(* % %) xs)))
    

    上面的函数创建了一个匿名函数,使用#() short hand syntax 对一个数字求平方。然后使用map 将该函数延迟映射到xs 集合中的每个项目上。因此,[1 2 3] 将变为 (1 4 9)reduce 函数获取每个项目并将+ 函数应用于它和当前总数,从而产生集合的总和。 (因为+有多个参数,在这种情况下你也可以使用apply。)

    如果使用其中一个线程宏 ->> 将所有内容放在一起,它开始看起来非常平易近人。 (尽管可以说,在这种情况下,我牺牲了一些可组合性来换取更高的可读性。)

    (defn super-sum-of-squares [n numbers]
      (->> (sort > numbers)
           (take n)
           (map #(* % %))
           (reduce +)))
    
    (super-sum-of-squares 2 [2 3 4]) ;;=> 25
    


    【讨论】:

      【解决方案2】:

      (defn greater [& args] (take 2 (sort > args)))

      (defn -main
        [& args]
        (let [greats (greater 2 3 4)
              sum (apply sum-of-squares greats)]
          sum))
      

      良好的 clojure 风格的一个关键是使用内置的序列操作。另一种方法是使用单一 cond 形式,而不是深度嵌套的 if 语句。

      def 不应在函数体内使用。

      一个函数应该返回一个可用的结果(如果你运行项目,-main返回的值将被打印出来)。

      apply 使用列表作为所提供函数的参数。

      【讨论】:

        【解决方案3】:

        要编写可读的代码,请尽可能使用该语言提供的功能: 例如 greater 可以定义为

        (defn greater [& args]
           (butlast (sort > args)))
        

        要使sum-of-squares 处理来自greater 的返回值,请使用参数解构

        (defn sum-of-squares [[x y]] 
           (+ (* x x) (* y y)))
        

        这需要知道参数序列中元素的数量,

        或定义 sum-of-squares 以将单个序列作为参数

        (defn sum-of-squares [args]
           (reduce + (map (fn [x] (* x x)) args)))
        

        【讨论】:

          猜你喜欢
          • 2011-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-04
          • 2020-01-26
          • 1970-01-01
          相关资源
          最近更新 更多