Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-11-25

GOOでL-99 (P23 指定した個数の要素をランダムに選択)

| 23:30 | GOOでL-99 (P23 指定した個数の要素をランダムに選択) - わだばLisperになる を含むブックマーク はてなブックマーク - GOOでL-99 (P23 指定した個数の要素をランダムに選択) - わだばLisperになる

以前は、L-99しかやってないブログと化していた程、L-99を色々なLISP方言で解いてみていましたが、どの方言でも完遂してはいません。

久々にちょっと久々に挑戦してみようかなと思い、ブログを眺めてみると、直近のエントリーは、2年前のGOOでの挑戦でした。

GOOもすっかり忘れているので、ちょっと書いて遊んでみることに。

久々に触ってみましたが、やっぱり色々と変わっています。

ちなみに、GOOはどういう言語かというと、Dylanの開発にも携わった、Jonathan Bachrach氏が開発した言語で、Dylan+Scheme+当時構想だけ発表されていたArcという感じのLISP方言です。

S式のDylanな感じもしつつ、Paul Graham氏の「生まれて3週間目のArc」を意識した機能と、短かすぎて逆に覚えられない関数名が特徴だと個人的には思っています。(GOOのページにもArcのパロディのような題名が多くあります)

ざっと目立つところだと

  • Arc/Perl風の短い関数名(と動作)
  • 基本的にメソッド主体で、総称関数
  • Dylanっぽい構文
  • Seriesが組み込み
  • 多値の代わりにタプル

というところでしょうか。

結構面白いので変わったLISP方言が好きな方にはお勧めです。

P23 (**) Extract a given number of randomly selected elements from a list.
    The selected items shall be returned in a list.
    Example:
    * (rnd-select '(a b c d e f g h) 3)
    (E D A)

    Hint: Use the built-in random number generator and the result of problem P20.
(df random-pop (u|<lst> => (tup <lst> <any>))
  (def rest (packer-fab <lst>))
  (def item (packer-fab <lst>))
  (def picknum (random (- (len u) 1)))
  (for ((e u)
        (i (from 0)))
    (if (= picknum i)
        (pack-in item e)
        (pack-in rest e)))
  (tup (packer-res rest)
       (1st (packer-res item))))

(df rnd-select (u|<lst> n|<int> => <lst>)
  (loc ((self1 (acc rest n)
          (if (or (zero? n) 
                  (empty? rest))
              acc
              (let (((tup nrest item) 
                     (random-pop rest)))
                (self1 (pair item acc)
                              nrest
                              (- n 1))))))
    (self1 () u n)))

実行例

(for ((i (range 1 <= 100)))
  (say out (rnd-select '(a b c d e f g h) 3) "\n"))
;-> 
;   (e g d)
;   (d e a)
;   (f d b)
;   (a b e)
;   (c a g)
;   (f d e)
;   (c f e)
;   (f g c)
;   (c f g)
;   (c g a)
;   (b e a)
;   (c a f)
;   (g f b)
;   (b a f)
;   (e d b)
;   (c a b)
;   (b f a)
;   (c g a)
;   (c b a)
;   (f e a)
;...

2009-03-20

RubyでL-99 (P9〜P13)

| 02:17 | RubyでL-99 (P9〜P13) - わだばLisperになる を含むブックマーク はてなブックマーク - RubyでL-99 (P9〜P13) - わだばLisperになる

適当につらつらと書いておりますが、折角なのでRSpecでテストも書きたいところ。

次は書いてみよう!

# P09 (**) Pack consecutive duplicates of list elements into sublists.
#     If a list contains repeated elements they should be placed in
#     separate sublists.
#
#     Example:
#     * (pack '(a a a a b c c a a d e e e e))
#     ((A A A A) (B) (C C) (A A) (D) (E E E E))
class Array
  def pack
    self.internal_pack([], [:dummy])
  end

  protected
  def internal_pack(ans, acc)
    head, *tail = self
    if self.empty?
      (ans + [acc])[1..-1]
    elsif head == acc[0]
      tail.internal_pack(ans ,acc + [head])
    else
      tail.internal_pack(ans + [acc], [head])
    end
  end
end

%w(a a a a b c c a a d e e e e).pack
#=> [["a", "a", "a", "a"], ["b"], ["c", "c"], ["a", "a"], ["d"], ["e", "e", "e", "e"]]

# P10 (*) Run-length encoding of a list.
#     Use the result of problem P09 to implement the so-called
#     run-length encoding data compression method. Consecutive
#     duplicates of elements are encoded as lists (N E) where N is the
#     number of duplicates of the element E.
#
#     Example:
#     * (encode '(a a a a b c c a a d e e e e))
#     ((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))
class Array 
  def encode
    self.pack.map do |x|
      [x.size, x.first]
    end
  end
end

%w(a a a a b c c a a d e e e e).encode
#=> [[4, "a"], "b", [2, "c"], [2, "a"], "d", [4, "e"]]

# P11 (*) Modified run-length encoding.
#     Modify the result of problem P10 in such a way that if an
#     element has no duplicates it is simply copied into the result
#     list. Only elements with duplicates are transferred as (N E)
#     lists.
#
#     Example:
#     * (encode-modified '(a a a a b c c a a d e e e e))
#     ((4 A) B (2 C) (2 A) D (4 E))
class Array 
  def encode_modified
    self.pack.map do |x|
      if 1 == x.size
        x.first
      else
        [x.size, x.first]
      end
    end
  end
end

%w(a a a a b c c a a d e e e e).encode_modified
#=> [[4, "a"], "b", [2, "c"], [2, "a"], "d", [4, "e"]]


# P12 (**) Decode a run-length encoded list.
#     Given a run-length code list generated as specified in problem
#     P11. Construct its uncompressed version.
class Array
  def decode
    self.inject([]) do |ans, x|
      ans + if x.class == Array
              Array.new(x[0], x[1])
            else
              Array.new(1, x)
            end
    end
  end
end

# 2
class Array
  def decode
    t = Array
    self.inject([]) do |ans, x|
      ans.+ x.class == Array ? Array.new(x[0], x[1]) : Array.new(1, x)
    end
  end
end

[[4, "a"], "b", [2, "c"], [2, "a"], "d", [4, "e"]].decode
#=> ["a", "a", "a", "a", "b", "c", "c", "a", "a", "d", "e", "e", "e", "e"]

# P13 (**) Run-length encoding of a list (direct solution).
#     Implement the so-called run-length encoding data compression
#     method directly. I.e. don't explicitly create the sublists
#     containing the duplicates, as in problem P09, but only count
#     them. As in problem P11, simplify the result list by replacing
#     the singleton lists (1 X) by X.
#
#     Example:
#     * (encode-direct '(a a a a b c c a a d e e e e))
#     ((4 A) B (2 C) (2 A) D (4 E))
class Array
  def encode_direct
    (self + [:dummy]).internal_encode_direct([], 1, :dummy)[1..-1]
  end

  protected
  def internal_encode_direct(ans, cnt, prev)
    head, *tail = self
    if self.empty?
      ans
    elsif head == prev
      tail.internal_encode_direct(ans, cnt + 1, head)
    else
      tail.internal_encode_direct(ans + [[cnt, prev]], 1, head)
    end
  end
end

%w(a a a a b c c a a d e e e e).encode_direct
#=> [[4, "a"], [1, "b"], [2, "c"], [2, "a"], [1, "d"], [4, "e"]]

2009-03-16

RubyでL-99 (P1〜P8)

| 23:59 | RubyでL-99 (P1〜P8) - わだばLisperになる を含むブックマーク はてなブックマーク - RubyでL-99 (P1〜P8) - わだばLisperになる

Rubyを勉強しております。

Rubyにリストが無いのとブロックの引数がローカルのスコープをつくらないところ(1.8では)にびっくりしました。

びっくりというより若干ショックでしたが、別にLispじゃないので当然のことでした。

ちょっとMatz Lispという言葉を真に受け過ぎていたようです(笑)

無駄に再帰していますが、L-99はそういう問題なのでRubyでも再帰。

色々分からないことが多く、まったくRubyっぽく書けてないですが、10年後位にはRubyっぽく書けるようになるのかもしれません。

# P01 (*) Find the last box of a list.
#     Example:
#     * (my-last '(a b c d))
#     (D)
class Array
  def my_last 
    head, *tail = self
    if tail.empty?
      self
    else
      tail.my_last
    end
  end
end

%w(1 2 3).my_last
#=> ["3"]

# P02 (*) Find the last but one box of a list.
#     Example:
#     * (my-but-last '(a b c d))
#     (C D)
class Array
  def last2
    _, *tail = self
    if tail[1..-1].empty?
      self
    else
      tail.last2
    end
  end
end

%w(a b c d).last2
#=> ["c", "d"]

#P03 (*) Find the K'th element of a list.
#    The first element in the list is number 1.
#    Example:
#    * (element-at '(a b c d e) 3)
#    C
class Array
  def element_at (pos)
    head, *tail = self
    if 0 > pos
      nil
    elsif self.empty? || 1 >= pos 
      head
    else
      tail.element_at(pos - 1)
    end
  end 
end

%w(1 2 3 4).element_at(2)
#=> "2"

# P04 (*) Find the number of elements of a list.
class Array
  def my_size
    _, *tail = self
    if self.empty?
      0
    else
      1 + tail.my_size
    end
  end
end

%w(1 2 3 4).my_size
#=> 4

# P05 (*) Reverse a list.
class Array
  def my_reverse
    head, *tail = self    
    if self.empty?
      []
    else
      tail.my_reverse + [head]
    end
  end
end

%w(1 2 3 4).my_reverse
#=> ["4", "3", "2", "1"]


#P06 (*) Find out whether a list is a palindrome.
#    A palindrome can be read forward or backward; e.g. (x a m a x).
class Array 
  def palindrome?
    self.my_reverse == self
  end
end

%w(x a m a x).palindrome?
#=> true

%w(x m a x).palindrome?
#=> false

# P07 (**) Flatten a nested list structure.
#     Transform a list, possibly holding lists as elements into a
#     `flat' list by replacing each list with its elements
#     (recursively).
#     Example:
#     * (my-flatten '(a (b (c d) e)))
#     (A B C D E)
#     Hint: Use the predefined functions list and append.
class Array
  def my_flatten
    head, *tail = self
    if self.empty?
      []
    elsif head.class == Array
      head.my_flatten + tail.my_flatten
    else
      [head] + tail.my_flatten
    end
  end
end

[1, [2, [3, 4], 5]].my_flatten
#=> [1, 2, 3, 4, 5]

# P08 (**) Eliminate consecutive duplicates of list elements.
#     If a list contains repeated elements they should be replaced
#     with a single copy of the element. The order of the elements
#     should not be changed.
#     Example:
#     * (compress '(a a a a b c c a a d e e e e))
#     (A B C A D E)
class Array 
  def _compress(prev, acc)
    head, *tail = self
    if self.empty?
      acc
    elsif head == prev
      tail._compress(head, acc)
    else
      tail._compress(head, acc + [head])
    end
  end

  def compress
    self._compress(:dummy, [])
  end
end

%w(a a a a b c c a a d e e e e).compress
#=> ["a", "b", "c", "a", "d", "e"]

2008-10-28

GOOでL-99 (P22 指定した範囲の数列のリスト)

| 00:15 | GOOでL-99 (P22 指定した範囲の数列のリスト) - わだばLisperになる を含むブックマーク はてなブックマーク - GOOでL-99 (P22 指定した範囲の数列のリスト) - わだばLisperになる

久々にGOOをひっぱり出してきてみました。何に由来するのか分かりませんが、GOOの作法はひどく覚えにくいと感じます。

多分、命名規則が、他のLISP方言と違うところにあるのではないかと思うのですが、この違いというのが、はっきりくっきり違うというのではなくて、微妙に違うというところが逆に覚えづらい気がします。あと関数名を短くしすぎなのも微妙に覚えづらい。あと引数の順番とか、微妙に逆。そしてマニュアルも微妙に独自。

今回は、総称関数にする必要もないので、関数です。define-functionの略のdfを使用。

(df my-range (start|<num> end|<num> by|... => <seq>)
  (def ans (packer-fab <lst>))
  (def by (if (empty? by) 1 (1st by)))
  (def r (if (<= start end)
             (range-by start <= end (op + _ by))
             (range-by start > end (op - _ by))))
  (for ((x r)) (pack-in ans x))
  (packer-res ans))

(my-range 4 9)
;=> (4 5 6 7 8 9))
(my-range 9 4)
;=> (9 8 7 6 5 4)
(my-range 3 3)
;=> '(3)

2008-10-22

ClojureでL-99 (P26 指定した個数を抜き出す組み合わせ)

| 17:01 | ClojureでL-99 (P26 指定した個数を抜き出す組み合わせ) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P26 指定した個数を抜き出す組み合わせ) - わだばLisperになる

Arcの[]や、Clojureの#()は、便利なんですが、更に進んで、mapの等で、`#(~(first coll) ~@%)みたいに書きたくなることが結構あります。どっちも今のところできません。というか、筋道立てて考えるとそもそも無理な相談という感じなのですが。

(defn 
  #^{:doc "P26 (**) Generate the combinations of K distinct objects 
chosen from the N elements of a list"
     :test (do (test= (combination 0 [1 2 3]) [])
               (test= (combination 88 []) [])
               (test= (count (combination 3 (range 12))) 220))}
  combination
  ([num coll]
     (cond (or (empty? coll) (>= 0 num)) 
           []
           (= 1 num) 
           (map list coll)
           :else
           `(~@(map #(cons (first coll) %)
                    (combination (- num 1) (rest coll)))
             ~@(combination num (rest coll))))))

2008-10-21

ClojureでL-99 (P25 ランダムに並び換え)

| 12:21 | ClojureでL-99 (P25 ランダムに並び換え) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P25 ランダムに並び換え) - わだばLisperになる

ちょっと鬱気味だなあと思ったら、L-99をやってませんでした。いけないいけない。L-99は心が安らぎます。

(defn 
  #^{:doc "P25 (*) Generate a random permutation of the elements of a list."
     :test (do (test= (rnd-permu []) [] ))}
; ---------
  rnd-permu
; ---------
  ([coll]
     (rnd-select coll (count coll))))

2008-10-16

ClojureでL-99 (P24 ロトくじ)

| 12:21 | ClojureでL-99 (P24 ロトくじ) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P24 ロトくじ) - わだばLisperになる

こういうランダムな場合に上手く条件をテストできる方法が知りたいと思ったり。

(defn
  #^{:doc "P24 (*) Lotto: Draw N different random numbers from the set 1..M."}
; ------------
  lotto-select
; ------------
  ([nums rng]
     (if (or (>= 0 rng) (>= 0 nums)) 
       nil
       (rnd-select (range 1 (+ 1 rng)) nums))))

2008-10-14

ClojureでL-99 (P23 ランダムに指定した個数の要素を選択)

| 06:37 | ClojureでL-99 (P23 ランダムに指定した個数の要素を選択) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P23 ランダムに指定した個数の要素を選択) - わだばLisperになる

P20で作ったremove-atを使用します。どうも、ぱっとしない出来。

(defn
  #^{:doc "P20 (*) Remove the K'th element from a list."
     :test (do (test= (rnd-select [] 3) [])) }
; ----------
  rnd-select
; ----------
  ([coll num]
     (loop [coll coll, cnt 1, len (length coll), ans [] ]
       (if (or (empty? coll) (> cnt num))
         ans
         (let [p (rand-int len)]
           (recur (remove-at coll (+ 1 p))
                  (+ 1 cnt)
                  (+ -1 len)
                  (conj ans (nth coll p))))))))

2008-10-13

ClojureでL-99 (P22 指定した範囲の数列のリスト)

| 06:26 | ClojureでL-99 (P22 指定した範囲の数列のリスト) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P22 指定した範囲の数列のリスト) - わだばLisperになる

fromの反対のdownfromとか定義してみましたが、もう一工夫という感じです。

ちなみに、標準で、Clojureには、rangeがありますが、このお題と同じ動きではありません。

(defn downfrom 
  ([start]
     (downfrom start 1))
  ([start step]
     (iterate #(- % step) start)))

(defn
  #^{:doc "P22 (*) Create a list containing all integers within a given range."
     :test (do (test= (my-range 4 9)
                      '(4 5 6 7 8 9))
               (test= (my-range 9 4)
                      '(9 8 7 6 5 4))
               (test= (my-range 3 3)
                      '(3)))}
; --------
  my-range
; --------
  ([start end]
     (cond (< start end) 
           (take (+ 1 (- start) end) (from start))
           (> start end) 
           (take (+ 1 start (- end)) (downfrom start))
           :else
           (list start))))

2008-10-10

ClojureでL-99 (P21 指定した位置に要素を挿入する)

| 06:42 | ClojureでL-99 (P21 指定した位置に要素を挿入する) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P21 指定した位置に要素を挿入する) - わだばLisperになる

前回と同じく無限リストを利用してみました。あとおまけで、EmacsのC-tのような操作でくるくるひっくり返してゆくパターンを思い付いたので書いてみました。

とりあえず、condの節の括弧はやっぱりあった方が良いと思うんですよねー。

(defn
  #^{:doc "P21 (*) Insert an element at a given position into a list."
     :test (do (test= (insert-at 'alfa '(a b c d) 2)
                      '(a alfa b c d))
               (test= (insert-at 'alfa [] 2)
                       '(alfa))        
               (test= (insert-at 'alfa '(a b c d) -2)
                      '(alfa a b c d))
               (test= (insert-at 'alfa '(a b c d) 100)
                      '(a b c d alfa))) }
; ---------
  insert-at
; ---------
  ([item coll pos]
     (let [len (count coll)]
       (cond 
        (empty? coll) 
        (list item)
        ;; 
        (>= 0 pos) 
        (cons item coll)
        ;; 
        (<= len pos) 
        (concat coll (list item))
        ;; 
        :else 
        (mapcat #(if (= pos %1) 
                   (list item %2)
                   (list %2))
                (from 1)
                coll)))))

;; 要素をくるくるひっくり返しつつ送ってゆくパターン
(defn insert-at
  ([item coll pos]
     (loop [coll (cons item coll), cnt pos, acc [] ]
       (if (or (>= 1 cnt) (nil? (rest coll)))
         (concat (reverse acc) coll)
         (recur (cons (first coll) (rrest coll))
                (+ -1 cnt)
                (cons (second coll) acc))))))

2008-10-09

ClojureでL-99 (P20 指定した要素を削除)

| 21:31 | ClojureでL-99 (P20 指定した要素を削除) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P20 指定した要素を削除) - わだばLisperになる

1..∞ な遅延リストと、リストを対応付けて解いてみました。

fromは、pfcから拝借(pfcのことなのでHaskellとかが元ネタかも…)。

fromの中のiterateは、初期値に関数を適用して、その結果にまた関数を適用して…な遅延リストを作成します。

stepはオプショナルにしていますが、clojureの場合、オプショナル引数は、オプションがある場合とない場合を分けて記述します。この辺がCLとはちょっと違うところ。

(defn
  #^{:doc "P20 (*) Remove the K'th element from a list."
     :test (do (test= (remove-at [] 3) [])
               (test= (remove-at '(a b c d) -3)
                      '(a b c d))
               (test= (remove-at '(a b c d) 100)
                      '(a b c d))
               (test= (remove-at '(a b c d) 2)
                      '(a c d))) }
; ---------
  remove-at
; ---------
  ([coll pos]
     (if (empty? coll)
       []
       (mapcat #(if (= pos %1) [] (list %2))
               (from 1)
               coll))))

(defn from 
  ([start]
     (from start 1))
  ([start step]
     (iterate #(+ step %) start)))

2008-10-06

ClojureでL-99 (P18 範囲切り出し)

| 21:31 | ClojureでL-99 (P18 範囲切り出し) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P18 範囲切り出し) - わだばLisperになる

Clojureには標準でsubseqがあります。

(defn
  #^{:doc "P18 (**) Extract a slice from a list."
     :test (do (test= (slice [] 3 7) [])
               (test= (slice '(a b c d e f g h i k) 3 7)
                      '(c d e f g))
               (test= (slice '(a b c d e f g h i k) -3 7)
                      (slice '(a b c d e f g h i k) 1 7))
               (test= (slice '(a b c d e f g h i k) -3 100)
                      '(a b c d e f g h i k))) }
; -----
  slice
; -----
  ([coll start end]
     (if (empty? coll)
       []
       (let [len (count coll), start (max start 1), end (min end len)]
         (loop [coll coll, pos 1, acc [] ]
           (if (or (empty? coll) (< end pos))
             (reverse acc)
             (recur (rest coll)
                    (+ 1 pos)
                    (if (<= start pos end)
                      (cons (first coll)
                            acc)
                      acc))))))))

2008-10-05

ClojureでL-99 (P17 指定した位置でリストを分割)

| 17:18 | ClojureでL-99 (P17 指定した位置でリストを分割) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P17 指定した位置でリストを分割) - わだばLisperになる

ありあわせの関数を使っちゃいけないということなので自前で処理しましたが、take、drop、take-while等々あるのでそれを使えば簡単に書けます。

(defn 
  #^{:doc "P17 (*) Split a list into two parts; the length of the first part is given."
     :test (do (test= (split [] 3) [[] []])
               (test= (split '(a b c d e f g h i k) 3)
                      '((a b c) (d e f g h i k)))
               (test= (split '(a b c d e f g h i k) -3)
                      '(()(a b c d e f g h i k)))
               (test= (split '(a b c d e f g h i k) 100)
                      '((a b c d e f g h i k) () ))) }
; -----
  split
; -----
  ([coll pos]
     (let [len (count coll)]
       (cond 
        (<= len pos) (list coll [])
        (>= 0 pos) (list [] coll)
        :else
        (loop [coll coll, cnt pos, head [] ]
          (if (or (empty? coll) (zero? cnt))
            (list (reverse head) coll)
            (recur (rest coll)
                   (+ -1 cnt)
                   (cons (first coll) head))))))))

2008-10-03

ClojureでL-99 (P16 周期Nで要素を間引く)

| 18:34 | ClojureでL-99 (P16 周期Nで要素を間引く) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P16 周期Nで要素を間引く) - わだばLisperになる

このお題では、関数名がdropとなっているのですが、dropはClojureにも存在するので、my-dropとしています。

clojure/dropの動作としては、SRFIのdropと同じです。

Clojureの場合、名前空間を分けられるので、競合を防ぐことも可能だと思いますが、とりあえず今回は大元のdropも使っていて紛らわしいので、それはなしの方向で。

(defn 
  #^{:doc "P16 (**) Drop every N'th element from a list."
     :test (do (test= (my-drop [] 3) [])
               (test= (my-drop '(a b c d e f g h i k) -1)
                      '(a b c d e f g h i k))
               (test= (my-drop '(a b c d e f g h i k) 0)
                      '(a b c d e f g h i k))
               (test= (my-drop '(a b c d e f g h i k) 3)
                      '(a b d e g h k))) }
; ----
  my-drop
; ----
  ([coll n]
     (if (empty? coll)
       []
       (loop [coll coll, acc [] ]
         (if-let block (butlast (take n coll))
           (recur (drop n coll) (concat acc block))
           (concat acc coll))))))

2008-10-02

ClojureでL-99 (P15 要素を任意回数複製する)

| 18:37 | ClojureでL-99 (P15 要素を任意回数複製する) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P15 要素を任意回数複製する) - わだばLisperになる

この問題は、2つ星で難しめということになっているのですが、Prologだとこういうのは難しかったりするんでしょうか。

(defn 
  #^{:doc "P15 (**) Replicate the elements of a list a given number of times."
     :test (do (test= (repli [] -1) [])
               (test= (repli [1 2] 0) nil)
               (test= (repli [1 2] -1) nil)
               (test= (repli '(a b c) 3)
                      '(a a a b b b c c c))) }
; -----
  repli
; -----
  ([coll n]
     (reduce #(concat %1 (take n (repeat %2)))
             []
             coll)))