Хобрук: Ваш путь к мастерству в программировании

Разбор подписанного запроса Facebook в Clojure

Я пытаюсь создать веб-сайт с Luminus, чтобы немного изучить Clojure. У меня был многолетний опыт работы с императивом, но только сейчас я начал заниматься функциональным программированием. Прямо сейчас я пытаюсь обработать объект signed_request из Facebook.

Согласно сайту я должен:

  1. Разделите строку на точку ("".") и получите вектор из 2 строк.
  2. Возьмите первую из этих строк, декодируйте ее с помощью base64 и сравните с секретом.
  3. Возьмите вторую из этих строк, декодируйте ее с помощью base64 и снова декодируйте с помощью JSON.

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

(defn parse-request [signed_request]
  ((clojure.string/split signed_request #"\.")
    ))

(defn redirect-page [signed_request]
  (layout/render "redirect.html"
                 {:parsed_request parse-request(signed_request)}))

(defroutes home-routes
  (GET "/" [] (home-page))
  (POST "/redirect" [signed_request] (redirect-page signed_request)))

redirect-page запускается, когда сервер получает POST-запрос, а затем берет signed_request и передает его в функцию parse-request. Каков функциональный подход к этому?


Ответы:


1

Я думаю, что основной ответ на ваш вопрос заключается в том, что функциональное программирование больше связано с вводом и выводом (подумайте о математической функции), тогда как императивное программирование, как правило, больше связано с побочными эффектами и изменяемыми данными. Вместо того, чтобы думать: «Что мне нужно делать?», подумайте: «Какая структура данных является моей целью и как мне определить ее?» У вас также могут быть побочные эффекты (например, печать), но обычно вы пишете чистые функции, которые принимают аргументы и что-то возвращают.

Деструктуризация — бесценный инструмент в Clojure, и здесь он может пригодиться. . Вы хотите разбить строку на две строки с помощью clojure.string/split, а затем сделать что-то с одной из строк и что-то еще с другой. Вы можете использовать привязку let для присвоения имен каждой строке, например:

(let [[str1 str2] (clojure.string/split signed-request #"\.")]
  (do-stuff-with-str1-and-str2))

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

(defn process-signed-request [signed-request]
  (let [[str1 str2] (clojure.string/split signed-request #"\.")]
    [(compare-fn (decode-with-base-64 str1) secret)
     (decode-with-json (decode-with-base-64 str2))]))

Обратите внимание, что приведенное выше частично является псевдокодом — вам нужно будет заменить compare-fn, decode-with-base-64, decode-with-json и secret фактическим кодом, представляющим эти вещи — это, или вы можете оставить его как есть и просто реализовать функции так, чтобы compare-fn, decode-with-base-64 и decode-with-json относятся к реальным функциям, которые вы пишете. Это распространенный подход в функциональном программировании — напишите короткую высокоуровневую функцию, определяющую решение проблемы, а затем вернитесь и напишите вспомогательные функции, которые она использует.

Кстати, есть еще несколько способов написать часть (decode-with-json (decode-with-base-64 str2)):

  1. ((comp decode-with-json decode-with-base-64) str2)
  2. (-> str2 decode-with-base-64 decode-with-json)

Я часто нахожу второй подход с использованием макроса потоковой передачи (-> или ->>) полезным, когда я знаю последовательность действий, которые мне нужно сделать с объектом, и я хочу, чтобы код читался интуитивно. Мне легче читать, например, «взять str2, декодировать его с помощью базы 64, а затем снова декодировать с помощью JSON».

Кроме того, это всего лишь мелочь, но обратите внимание на порядок скобок, когда пишете код на Clojure. В том виде, в котором у вас сейчас есть код, круглые скобки должны выглядеть так:

(defn parse-request [signed_request]
  (clojure.string/split signed_request #"\."))

(defn redirect-page [signed_request]
  (layout/render "redirect.html"
                 {:parsed_request (parse-request signed_request)}))

Если у вас большой опыт работы с императивами, вы, вероятно, настолько укоренились в синтаксисе fn(x), что случайно вводите его вместо синтаксиса (fn x) Lisp, который использует Clojure.

И пока я придираюсь, в Clojure идиоматично использовать дефисы вместо подчеркивания для именования символов. Итак, я бы переименовал signed_request и :parsed_request в signed-request и :parsed-request.

Надеюсь, это поможет!

14.04.2014
  • Отличный ответ, спасибо! Похоже, это займет гораздо больше времени, чем я думал, может, мне стоит воздержаться от этого во время экзамена, ха-ха. 15.04.2014
  • Нет проблем :) Если вы хотите больше узнать о функциональном программировании, подумайте о том, чтобы прочитать Изучите Haskell. Это книга о Haskell, а не о Clojure, но это отличное введение в функциональное программирование, которое начинается с квадрата 1. На самом деле я сначала немного изучил Haskell, прежде чем я изучил Clojure, и это значительно упростило понимание концепций FP. 15.04.2014
  • Новые материалы

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

    Разбор строк запроса в vue.js
    Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

    Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
    «Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

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