Clojure 用Monad来解决NULL检查的问题

之前用Clojure写了一个小工具来抓取Youtube视频的下载地址, 功能是分析Google提供的API中的数据, 其实就是一个JSON对象, 转换为Clojure map, 然后从中提取想要的数据.

例如

 
 
(defn get-youtube-video [parsed]
  (let [url_encoded_fmt_stream_map (:url_encoded_fmt_stream_map parsed)
        adaptive_fmts (:adaptive_fmts parsed)
        splited-stream (.split (java.net.URLDecoder/decode url_encoded_fmt_stream_map "UTF-8") ",")
        splited-adaptive_fmts (.split (java.net.URLDecoder/decode adaptive_fmts "UTF-8") ",")
       ]
    (doall (map #(youtube-stream-handle %) splited-stream))
    (print "===============adaptive_fmts starts\n")
    (map #(youtube-stream-handle %) splited-adaptive_fmts)
  )
)
 

代码工作的一直很好, 知道某一天报错, decode函数收到null, 经检查, adaptive_fmts这个字段不存在, 原因要么是Google的数据格式改变了, 要么是某些视频没有这个字段.

最容易想到的办法是用if来检查null, 但我已经了解了Monad, 我知道这样做会让代码更难看, 而用Maybe Monad来做的话会更好.

Cloure其实自带一个monad库的, 但是我决定用下面的这个库, 因为教程很好理解, 马上就可以用到. 修改后如下

 
(use 'clojure.algo.monads)
(defn get-youtube-video [parsed]
  (let [url_encoded_fmt_stream_map (:url_encoded_fmt_stream_map parsed)
        splited-stream (.split (java.net.URLDecoder/decode url_encoded_fmt_stream_map "UTF-8") ",")
       ]
    (doall (map #(youtube-stream-handle %) splited-stream))
 
    (domonad maybe-m
      [adaptive_fmts (:adaptive_fmts parsed)
       splited-adaptive_fmts (.split (java.net.URLDecoder/decode adaptive_fmts "UTF-8") ",")
      ]
      (map #(youtube-stream-handle %) splited-adaptive_fmts)
    )
  )
)