Почему clojure пытается разрешить этот символ? - PullRequest
0 голосов
/ 10 сентября 2018

Я работаю над упражнением «Числа Армстронга» на дорожке Clojure в упражнении.Число Армстронга - это число, равное сумме его цифр, возведенной в степень числа цифр.153 - это число Армстронга, потому что: 153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153.154 не является числом Армстронга, потому что: 154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190.

Тестовый файл для этого упражнения вызовет функцию armstrong?, передаст число и ожидает истину, если число является числом Армстронга.Я уже решил проблему с этим кодом:

(ns armstrong-numbers)

(defn pow [a b]
  (reduce * 1 (repeat b a)))

(defn armstrong? [num]
  (->> num
       (iterate #(quot % 10))
       (take-while pos?)
       (map #(mod % 10))
       ((fn [sq]
          (map #(pow % (count sq))
               sq)))
       (apply +)
       (= num)))

, но сейчас я пытаюсь изменить код.Вот как я хотел бы, чтобы код выглядел следующим образом:

(ns armstrong-numbers
  (:require [swiss.arrows :refer :all]))

(defn pow [a b]
  (reduce * 1 (repeat b a)))

(defn armstrong? [num]
  (-<>> num
        (iterate #(quot % 10))
        (take-while pos?)
        (map #(mod % 10))
        (map #(pow % (count <>))
             <>)
        (apply +)
        (= num)))

Ссылка на требуемый выше пакет: https://github.com/rplevy/swiss-arrows.

В первом разделе кода я создаю неявную функцию внутримакрос последнего потока, потому что последовательность, возвращаемая из формы карты, необходима в двух разных местах во второй форме карты.Эта неявная функция работает просто отлично, но я просто хотел сделать код более гладким.Но когда я тестирую второй блок кода, я получаю следующую ошибку: java.lang.RuntimeException: Unable to resolve symbol: <> in this context.

Я получаю эту ошибку, использую ли я #(), partial или fn внутри формы второй карты.Я выяснил, что, поскольку все предшествующие являются макросами (или специальной формой в случае fn), они не могут разрешить <>, потому что это имеет смысл только для макроса -<>>, который вызывается на более позднем этапеmacroexpansion.Но почему #(), partial и fn пытаются разрешить этот символ вообще?Насколько я вижу, у них нет причин знать, что это за символ или какова его цель.Все, что им нужно сделать, это вернуть этот символ, переставленный в правильные s-выражения.Так почему же clojure пытается разрешить этот (<>) символ?

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

Документация для -<>> совершенно ясна, что она ведет себя не так, как вы хотели бы:

"алмазное копье": вставка x верхнего уровня вместо одиночного позиционный символ «<>» в резьбовой форме, если имеется, в противном случае в основном ведут себя как последний поток макроса. Также работает с хеш-литералами и векторы. "

выполняет замену:

  • одного символа
  • На верхнем уровне резьбовой формы

Ваш пример, желающий использовать его для нескольких символов, вложенных в подчиненные формы, таким образом, не будет работать.

0 голосов
/ 10 сентября 2018

Символ <> действителен только на самом верхнем уровне предложения (плюс литералы для набора, карты, вектора непосредственно в нем). -<> и -<>> не устанавливают привязки (как в let) для <>, но выполняют вставку кода во время расширения макроса.

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

Если вам нужна реальная привязка, вы можете использовать as-> (из clojure.core).

0 голосов
/ 10 сентября 2018

Вы допустили ошибку, исключив символ <> в большинстве ваших форм в случае ошибки. Вот рабочая версия (с использованием аналогичного макроса it-> вместо швейцарских стрелок). Я также немного почистил pow.

(defn pow-int [a b] (Math/round (Math/pow a b)))

(defn armstrong? [num]
  (it-> num
        (iterate #(quot % 10) it)
        (take-while pos? it)
        (map #(mod % 10) it)
        (map #(pow-int % (count it)) it)
        (apply + it)
        (= it num)))

(armstrong? 153) => true
(armstrong? 154) => false

Вы можете найти документы по it-> здесь .


Если вы опустите аргумент (collection) для функции, подобной map, она возвращает преобразователь; из документов :

(map f)(map f coll)(map f c1 c2)(map f c1 c2 c3)(map f c1 c2 c3 & colls)

Returns a lazy sequence consisting of the result of applying f to
the set of first items of each coll, followed by applying f to the
set of second items in each coll, until any one of the colls is
exhausted.  Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments. Returns a transducer when
no collection is provided.

И, всегда обращайтесь к Шпаргалке Clojure!

...