代码之家  ›  专栏  ›  技术社区  ›  anon

在不到50行的clojure中,你做的最有用的事情是什么?

  •  25
  • anon  · 技术社区  · 6 年前

    Clojure似乎很喜欢它成为一个流行的口齿不清的人。我想知道到底有多少人采用它来解决他们遇到的一些小而实际的问题。因为Clojure没有进入 Pleac 我认为,如果人们把他们在Clojure解决的问题的小解决方案公布出来,那就太好了。

    9 回复  |  直到 11 年前
        1
  •  15
  •   Brian Carper    16 年前

    这将通过打印天气预报 Yahoo! Weather .

    (ns weather
      (:use (clojure [xml :only [parse]] [zip :only [xml-zip]])
            (clojure.contrib duck-streams str-utils pprint)
            (clojure.contrib.zip-filter xml)))
    
    (defn fetch-xml [uri]
      (xml-zip
       (parse
        (org.xml.sax.InputSource.
         (java.io.StringReader.
          (slurp* (java.net.URI. (re-gsub #"\s+" "+" (str uri)))))))))
    
    (defn yahoo-weather
      ([loc-code] (yahoo-weather loc-code "c"))
      ([loc-code unit]
         (let [rss (fetch-xml (str "http://weather.yahooapis.com/forecastrss?p=" loc-code "&u=" unit))]
           (if (= (text (xml1-> rss :channel :item :title)) "City not found")
             "City not found.  Go to http://weather.yahoo.com/, search for your city, and look in the URL for the location code."
             (let [[units loc wind atm ast] (map #(xml1-> rss :channel (keyword (str "yweather:" %)))
                                                 ["units" "location" "wind" "atmosphere" "astronomy"])
                   conditions (xml1-> rss :channel :item :yweather:condition)
                   date (re-find #"\d+:\d+.*" (xml1-> rss :channel :item :pubDate text))
                   fors (xml-> rss :channel :item :yweather:forecast)]
               (cl-format true
    "Weather for ~a, ~a (~a)
        Temperature: ~a\u00B0 ~a
         Wind Chill: ~a\u00B0 ~a, ~a ~a
         Conditions: ~a
           Humidity: ~a%
          Barometer: ~a ~a
     Sunrise/Sunset: ~a / ~a
    
    Forecast:
    ~{  ~{~a: ~a. Hi ~2d, Lo ~2d.~}~^~%~}
    "
                          (attr loc :city) (attr loc :region) date
                          (attr conditions :temp) (attr units :temperature)
                          (attr wind :chill) (attr units :temperature) (attr wind :speed) (attr units :speed)
                          (attr conditions :text)
                          (attr atm :humidity)
                          (attr atm :pressure) (attr units :pressure)
                          (attr ast :sunrise) (attr ast :sunset)
                          (map #(list (attr % :day)
                                      (attr % :text)
                                      (attr % :high)
                                      (attr % :low))
                               fors)))))))
    

    例如:

    user> (weather/yahoo-weather "CAXX0328")
    Weather for North Vancouver,  (10:00 am PDT)
        Temperature: 14° C
         Wind Chill: 14° C, 8.05 kph
         Conditions: Light Rain Shower
           Humidity: 88%
          Barometer: 1018 mb
     Sunrise/Sunset: 6:01 am / 8:32 pm
    
    Forecast:
      Thu: Few Showers. Hi 18, Lo 12.
      Fri: AM Showers. Hi 19, Lo 12.
    nil
    
        2
  •  9
  •   Jeff    16 年前

    它本身并不是特别有用,但其思想类似于JavaScript中的JSON——您可以在文件系统中来回移动Clojure数据结构。采用于 Practical Common Lisp's Database 例子:

    (ns storage (:import (java.io File PushbackReader FileReader FileWriter)))
    
    (defn load-data
      "Loads data from the given file."
      [filepath]
      (do
        ;; the let block creates the file if it doesn't exist
        ;; reader throws an exception if there's no parsable data struct
        (let [file (new File filepath)]
          (if (not (.exists file))
            (do
              (.createNewFile file)
              (doto (new FileWriter filepath) (.write "{}") .close))))
        (read (new PushbackReader (new FileReader filepath)))))
    
    (defn dump-data
      "Exports data structure to a file."
      [filepath data]
      (doto (new FileWriter filepath) (.write (str data)) .close))
    

    示例用法:

    user=> (dump-data "test.dat" {:a [1 2 3] :b "hello" :c true})
    #<FileWriter java.io.FileWriter@186df0f>
    
    user=> (load-data "test.dat")
    {:a [1 2 3], :b "hello", :c true}
    

    当然比为程序编写自己的(复杂的)保存机制要好。我相信仅仅通过改变一些通过Java提供的读者来阅读字符串是可能的。

        3
  •  6
  •   Brian Carper    16 年前

    这将从图像创建缩略图。图像可以是本地文件、远程URL或其他任何文件 javax.imageio.ImageIO 可以阅读(谢谢JAVA!).输出可以是任何图像格式 javax.imageio.imageio图像 可以写。

    (use '(clojure.contrib java-utils))
    (defn make-thumbnail
      "Given an input image (File, URL, InputStream, ImageInputStream),
       output a smaller, scaled copy of the image to the given filename.
       The output format is derived from the output filename if possible.
       Width should be given in pixels."
      ([image out-filename width]
         (if-let [format (re-find #"\.(\w+)$" out-filename)]
           (make-thumbnail image out-filename width (nth format 1))
           (throw (Exception. "Can't determine output file format based on filename."))))
      ([image out-filename width format]
         (let [img (javax.imageio.ImageIO/read image)
               imgtype (java.awt.image.BufferedImage/TYPE_INT_RGB)
               width (min (.getWidth img) width)
               height (* (/ width (.getWidth img)) (.getHeight img))
               simg (java.awt.image.BufferedImage. width height imgtype)
               g (.createGraphics simg)]
           (.drawImage g img 0 0 width height nil)
           (.dispose g)
           (javax.imageio.ImageIO/write simg format (as-file out-filename)))))

    从本地PNG创建JPG缩略图:

    (make-thumbnail (java.io.File. "some-image.png") "thumb.jpg" 150)
    

    从远程JPG创建GIF缩略图:

    (make-thumbnail (java.net.URL. "http://blog.stackoverflow.com/wp-content/uploads/justice-league-small.jpg") "small.gif" 250)
    
        4
  •  6
  •   TJ.    16 年前

    99瓶啤酒

    
    (defn bottles [n & [capitalize]]
      (str (if (> n 0) n (if capitalize "No more" "no more"))
        " bottle" (if (= 1 n) "" "s") " of beer" ))
    
    (defn bot-wall [n & cap] (str (bottles n cap) " on the wall"))
    
    (defn sing
      ;  Default is 99 times.
      ([]  (sing 99))
      ([stock]
        (doseq [i (range stock -1 -1)]
          (printf "%s, %s.\n%s.\n\n"
            (bot-wall i true) (bottles i)
            (apply str
              (if (> i 0)
                ["Take one down and pass it around, " (bot-wall (dec i))]
                ["Go to the store and buy some more, " (bot-wall stock)]
              ))))))
    
    (sing)
    

    http://99-bottles-of-beer.net/language-clojure-1996.html

        5
  •  6
  •   faran    8 年前

    我在Clojure中为自己写的最有用的东西是几乎微不足道的函数:

    (defn tally-map
     " Create a map where the keys are all of the unique elements in the input
       sequence and the values represent the number of times those elements
       occur. Note that the keys may not be formatted as conventional Clojure
       keys, i.e. a colon preceding a symbol."
      [aseq]
      (apply merge-with + (map (fn [x] {x 1}) aseq)))
    

    在我做的工作中,我一直使用这个。对于柱状图非常有用。

    Brian Carper 很好地提出了以下功能的改进形式。

    (defn tally-map [coll]
      (reduce (fn [h n]
                (assoc h n (inc (or (h n) 0))))
              {} coll))
    
        6
  •  4
  •   Ronald    15 年前

    Clojure可能有一个强大的功能,但当我发现这一点时,我真的很兴奋:

    (defn pow [base exp] (reduce * (replicate exp base)))
    
        7
  •  2
  •   LukLed    13 年前

    写Swing应用程序时,jmenubar的东西总是很烦人。多亏了多伦/地图,一切都变得简单多了:

    (let [menus
    [
     {:name "File" :mnemonic \F
      :items
      [
       {:name "Open" :mnemonic \O :fn file-open}
       :separator 
       {:name "Exit" :mnemonic \x :fn file-exit}
       ]
      }
    
     {:name "Help" :mnemonic \H
      :items
      [
       :separator 
       {:name "About..." :mnemonic \A :fn help-about}
       ]
      }
     ]
    
    menu-fns
    (into
     {}
     (mapcat
      (fn [menu]
        (map
         (fn [item] [(:name item) (:fn item)])
         (:items menu)))
      menus))
    
    ui-frame
    (proxy [JFrame ActionListener] ["UI Frame"]
      (actionPerformed
       [event]
        (let [command (.getActionCommand event)
          menu-fn (get menu-fns command)]
    
          ;; Handle menu commands
          (if menu-fn
        (apply menu-fn [this]))
          ))
      )
    ]
    
    (defn new-menu [listener]
      (let [menubar (JMenuBar.)]
    (dorun
     (map
      (fn [x]
        (let [menu (JMenu. (:name x))]
          (.setMnemonic menu (int (:mnemonic x)))
          (.add menubar menu)
          (dorun
           (map
        (fn [item]
          (if (= :separator item)
            (.addSeparator menu)
            (let [menu-item
              (if (:mnemonic item)
                (JMenuItem. (:name item) (int (:mnemonic item)))
                (JMenuItem. (:name item)))]
              (.addActionListener menu-item listener)
              (.add menu menu-item))))
        (:items x)))))
      menus))
    
    menubar))
    

    现在我不需要子菜单,但这是对 new-menu 得到它们。此外,添加图标、活动/非活动状态等只是 menus .

        8
  •  1
  •   galdre    11 年前

    好吧,这个代码真的是为我和其他人设计的。前几天我花了二十分钟把它拼凑在一起上了一门关于马尔可夫过程的课程。我觉得它确实有用。我用它来说服教授我对一个问题的理论分析是正确的。说实话,很酷(我想!)实际上只是第一个函数, sample .在我的许多项目中,我都使用这样的函数,当我匆忙地修改这个函数时,我偶然发现了我的最佳解决方案。

    (defn sample
       "Samples once a discrete random distribution defined by
       a vector. E.g., (sample [0.25 0.2 0.1 0.45]) should output
       '0' 25% of the time, '1' 20% of the time, etc."
       [p]
       (let [r (rand)]
          (count (take-while #(< % r) (reductions + p)))))
    (defn transition
       "Given a transition matrix and a history vector, returns
       the history with an additional time step added."
       [m h]
          (conj h (sample (nth m (last h)))))
    (defn process-gen
       "Takes a transition probability matrix, initial state
       probabilities, and a function.
       The initial state probs should take the form [p .. q].
       The function should accept the full process history
       and return true if the process should stop.  
       Returns a function of no arguments that returns a full
       simulated history of the process."
       [m i f]
       (fn [] (loop [h [(sample i)]] (if (f h) h (recur (transition m h))))))
    (defn transition2
       "Given a transition matrix and the current state, returns
        a sampled state for the next time step."
       [m s]
       (sample (nth m s)))
    (defn lazy-process
       "Takes a transition probability matrix, initial state
       probabilities, and a function.
       The initial state probs should take the form [p .. q].
       Returns a function which, when run, produces an infinite
       lazy list sampling the process."
       [m i]
       (fn [] f
          ([] (f (sample initial)))
          ([s] (let [i (transition2 m s)]
                (cons i (lazy-seq (f i)))))))
    

    删除注释:

    (defn sample [p]
       (let [r (rand)]
          (count (take-while #(< % r) (reductions + p)))))
    (defn transition [m h]
          (conj h (sample (nth m (last h)))))
    (defn process-gen [m i f]
       (fn [] (loop [h [(sample i)]] (if (f h) h (recur (transition m h))))))
    (defn transition2 [m s]
       (sample (nth m s)))
    (defn lazy-process-gen [m i]
       (fn [] f
          ([] (f (sample initial)))
          ([s] (let [i (transition2 m s)]
                (cons i (lazy-seq (f i)))))))
    

    实例使用:

    user=>(def squirrel-matrix [[0.8797 0.0212 0.0981 0.0010]
    [0.0382 0.8002 0.0273 0.1343]
    [0.0527 0.0041 0.8802 0.0630]
    [0.0008 0.0143 0.0527 0.9322]])
    user=>(def my-process (process-gen squirrel-matrix [1 0 0 0] #(and (> (count %) 1) (= 0 (last %)))))
    user=> (/ (reduce + (map (comp dec count) (repeatedly 1000000 my-process))) 1000000.)
    5.820319
    user=> (let [hs (reduce + (filter #(> % 1) (map (comp dec count) (repeatedly 1000000 my-process))))] (/ (reduce + hs)) (count hs)))
    5002699/120880 ; ~41.386
    

    这两个数字通过过度模拟回答了问题的两种不同解释。 here .

    我必须承认我为你们清理了一点代码。我写这篇文章的那天,我发现Clojure允许在符号名中使用Unicode。我可能去了 小的 在修改语言时太过分了。;-)那么……前三个函数在我的文件中实际上是这样的!

    (Λ σ [p] (let [r (rand)] (|| (take-while #(< % r) (∮ + p)))))
    (Λ Δ [Ξ ξ] (⊞ ξ (σ (§ Ξ (last ξ)))))
    (Λ Π [Ξ i ω] (λ [] (⟳ [ξ [(σ i)]] (⇒ (ω ξ) ξ (⟲ (Δ Ξ ξ))))))
    
        9
  •  1
  •   galdre    11 年前

    这次更严肃的回答是:

    repl stacktrace函数只显示8行,这常常让我很沮丧。因此,这现在在我所有项目的开发文件中:

    (defn stack
       [n]
       (clojure.stacktrace/print-stack-trace (clojure.stacktrace/root-cause *e) n))
    

    我想要 argmin argmax 总是 .

    (defn argmin
       ([f x] x)
       ([f x y] (if (< (f x) (f y)) x y))
       ([f x y & more] (reduce (partial argmin f) (argmin f x y) more)))
    (defn argmax
       ([f x] x)
       ([f x y] (if (> (f x) (f y)) x y))
      ([f x y & more] (reduce (partial argmax f) (argmax f x y) more)))
    

    最后,为了可靠地评估算法,我经常在数据集上使用此函数:

    (defn kfolds
       "Given an integer k and a collection of data, this
       partitions the data into k non-overlapping collections,
       then returns a list of length k, where the ith item is
       itself a list of two items: 
          (1) the union of all but the ith partition
          (2) the ith partition.
       If (count data) is not divisible by k, a few points (< k)
       will be left out."
       [k data]
       (let [total (count data)
             fold-size (int (/ total k))
             folds-test (take k (partition fold-size fold-size [] data))
             folds-train (map #(apply concat %)
                            (map #(take (dec k)
                                     (drop %
                                           (cycle folds-test)))
                               (range 1 (inc k))))]
             (map list folds-train folds-test)))
    
    推荐文章