函数式编程源自弱小人类对抗浩瀚宇宙的迫切需求steemCreated with Sketch.

in programming •  7 years ago 

以Common Lisp程序为例。

一个Common Lisp程序本来可以只是一个函数,但为了便于人类进行阅读,故将一个函数拆分为多个小函数,至于模块化重用性易调试,实乃意想不到的收获。如果将整个程序只写在一个函数里,因为用于显示程序的屏幕是有限的,肉眼的视角是有限的,肉眼一次性能捕捉到的内容将非常受限,那么每次移动屏幕和视觉所获取的信息都会大打折扣。物理上屏幕和生理上视角的双重局限,压迫人类进行手动拆分函数过程,然究其根本,实为“渺沧海之一粟,寄蜉蝣于天地”的无奈。小小的人,却欲观尽浩渺苍穹,茫茫千万年,前赴后继,何其悲壮。也许世界的全部,就是人类自身,就是万千众生,曰“一花一世界”,不正如是?

函数"string-to-html",目的是将大段的文字转换成符合"HTML"语法的文字,如果是一段文字就添加"<p></p>"标签,如果是空行,就添加"<p><br/></p>"标签。

例如,给定大段文字:

(defparameter *string-to-html*
  "0

1")

需要转换成:

"<p>0</p><p><br/></p><p>1</p>"

不把函数分拆时,把所有操作都包含在一个函数里:

(defun string-to-html (string)
  (format nil "~{<p>~A</p>~}"
          (mapcar (lambda (i)
                    (if (or (null i)
                            (and (stringp i)
                                 (= (length i)
                                    0)))
                        "<br/>"
                        i))
                  (let ((var nil)
                        (stream (make-string-input-stream string)))
                    (do ((line (read-line stream nil 'eof)
                               (read-line stream nil 'eof)))
                        ((eql line 'eof))
                      (push line var))
                    (reverse var)))))

调用:

(string-to-html *string-to-html*)

"<p>0</p><p><br/></p><p>1</p>"

拆分后的全局函数:

(defun null-string-p (string)
  (or (null string)
      (and (stringp string)
           (= (length string)
              0))))

(defun %%string-to-html-1 (string)
  (let ((var nil)
        (stream (make-string-input-stream string)))
    (do ((line (read-line stream nil 'eof)
               (read-line stream nil 'eof)))
        ((eql line 'eof))
      (push line var))
    (reverse var)))

(defun %string-to-html-1 (%%string-to-html-1)
  (mapcar (lambda (i)
            (if (null-string-p i)
                "<br/>"
                i))
          %%string-to-html-1))

(defun string-to-html-1 (%string-to-html-1)
  (format nil "~{<p>~A</p>~}"
          %string-to-html-1))

调用时:

(string-to-html-1
 (%string-to-html-1
  (%%string-to-html-1 *string-to-html*)))

"<p>0</p><p><br/></p><p>1</p>"

拆分后的局部函数:

(defun string-to-html-2 (string)
  (labels ((null-string-p (string)
             (or (null string)
                 (and (stringp string)
                      (= (length string)
                         0))))
           (%%string-to-html-2 (string)
             (let ((var nil)
                   (stream (make-string-input-stream string)))
               (do ((line (read-line stream nil 'eof)
                          (read-line stream nil 'eof)))
                   ((eql line 'eof))
                 (push line var))
               (reverse var)))
           (%string-to-html-2 (%%string-to-html-2)
             (mapcar (lambda (i)
                       (if (null-string-p i)
                           "<br/>"
                           i))
                     %%string-to-html-2)))
    (format nil "~{<p>~A</p>~}"
            (%string-to-html-2
             (%%string-to-html-2 string)))))

对比上述三种实现方式,分拆成全局函数时:

  • 成本
    • 需要输入更多的字符和行数,曰物理成本:(90-54)/54=2/3
      • 不分拆函数时字符:Region has 16 lines, 54 words, and 661
        characters.
      • 分拆后的局部函数:Region has 23 lines, 90 words, and 899
        characters.
      • 分拆后的全局函数:Region has 25 lines, 90 words, and 673
        characters.
    • 需要为多个小函数选择合适的名字,曰精神成本:用一个名字抽象化一个过程
      • 需结合函数的功能
      • 需调试时能见函数名就知功能
  • 效益
    • 易阅读:小块内容,缩进量少,显而易见的函数功能。
    • 模块化:使用返回值时只用确保参数符合要求,自然就返回合适的值。
    • 重用性:直接分离出某个小函数,用于别的项目。
    • 易调试:函数出错时容易定位到某个小函数 -

从上述的数据里可见,为了所谓的效益,人类宁可多打点字,尽管要增加2/3的打字量,宁可想个好名字,尽管要多费点心神去打磨。

赞美函数式编程本身就像宣扬人类有多么无奈、弱小一样,生怕强大的宇宙不知道人类有多么菜,但这确确实实是弱小人类对抗浩瀚宇宙的有效举措,再说了,任何函数式的程序天生就有拿来即用的禀赋,于人于己都有益处,多费时间就多费时间吧,人类在抽象这条路上算是越走越远了。

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!