Подтвердить что ты не робот

Какая самая полезная вещь, которую вы сделали в менее чем 50 строках Clojure?

Clojure Кажется, что это может быть хорошим выстрелом в популярность Lisp. Мне было интересно, сколько людей фактически приняли его, чтобы решить некоторые из небольших, но реальных проблем, с которыми они столкнулись. Поскольку Clojure не имеет записи в Pleac, я подумал, что было бы здорово, если бы люди разместили свои небольшие решения проблем, которые они решили в Clojure.

4b9b3361

Ответ 1

Отправляет прогноз погоды через Yahoo! Погода.

(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

Не особенно полезен сам по себе, но идея похожа на JSON в Javascript - вы можете перемещать структуры данных Clojure в файловую систему и из нее. Принято из Практическое общее Lisp База данных:

(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 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 [email protected]>

user=> (load-data "test.dat")
{:a [1 2 3], :b "hello", :c true}

Разумеется, ударит ваш собственный (сложный) механизм сохранения вашей программы. Я уверен, что чистое чтение из строки возможно только путем изменения некоторых из читателей, предоставляемых через Java.

Ответ 3

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

Ответ 4

Это создает эскиз изображения. Изображение может быть локальным файлом, удаленным 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)))))

Создайте миниатюру JPG из локального PNG:

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

Создайте миниатюру GIF с удаленного JPG:

(make-thumbnail (java.net.URL. "http://blog.stackoverflow.com/wp-content/uploads/justice-league-small.jpg") "small.gif" 250)

Ответ 5

Самая полезная вещь, которую я написал для себя в 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)))

Я все время использую это в своей работе. Очень полезно для гистограмм.

Брайан Карпер был достаточно любезен, чтобы предложить следующую улучшенную форму функции.

(defn tally-map [coll]
  (reduce (fn [h n]
            (assoc h n (inc (or (h n) 0))))
          {} coll))

Ответ 6

Clojure, вероятно, имеет функцию мощности, но я был очень взволнован, когда понял:

(defn pow [base exp] (reduce * (replicate exp base)))

Ответ 7

Написание приложений Swing, материал JMenuBar всегда раздражает. Благодаря dorun/map это намного проще:

(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

Ну, этот код действительно предназначался для меня и для кого-то другого. На днях я бросил его за двадцать минут на курс по марковским процессам. Я определенно нашел это полезным. Я использовал его, чтобы убедить профессора в том, что мой теоретический анализ проблемы был верным. Честно говоря, крутой бит (я думаю!) Действительно является первой функцией, 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

Эти два числа отвечают посредством чрезмерной симуляции двух разных интерпретаций вопроса здесь.

Должен признаться, что я немного очистил свой код для вас. В тот день, когда я написал это, я обнаружил, что Clojure разрешил Unicode в именах символов. Возможно, я немного изменил язык, изменив язык.;-) Итак... эти первые три функции на самом деле выглядят так в моем файле!

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

Ответ 9

На этот раз более серьезный ответ:

Я часто расстраиваюсь функцией REPL stacktrace, отображающей только восемь строк. Итак, это теперь находится в файле разработки для всех моих проектов:

(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)))