Fork me on GitHub
#clojure-russia
<
2017-04-25
>
rustam.gilaztdinov08:04:03

А кто-нибудь из юзеров spacemacs'а может помочь с биндингами? Хочу 'cider-eval-defun-at-point забиндить на два пробела, полазил по ~/.emacs.d/layers/+lang/clojure/packages.el но чото не могу разобраться Может кто делал уже?

artemyarulin08:04:44

два пробела, это как? просто два пробела?

rustam.gilaztdinov08:04:34

вместо SPC m e f --> SPC SPC

artemyarulin08:04:58

а если надо 2 пробела сделать в тексте? хотя не помню последний раз когда такое нужно было… расскажи потом если найдешь, может тож что-нить забайндю

rustam.gilaztdinov08:04:44

ок, хорошо

delaguardo08:04:06

(dolist (m '(clojure-mode
             clojurec-mode
             clojurescript-mode
             clojurex-mode
             cider-repl-mode
             cider-clojure-interaction-mode))
  (spacemacs/set-leader-keys-for-major-mode m
    "SPC" 'cider-eval-defun-at-point))

delaguardo08:04:49

как то так, но это переопределяет биндинг самого спэйсмакса, M-x

delaguardo08:04:33

@artemyarulin с набором текста это не коррелирует, работает только в normal-mode

delaguardo08:04:27

кстати, для краткости можно вместо SPC m e f набирать , e f

artemyarulin08:04:17

ну набор текста я имею ввиду если в коменте написать надо например

rustam.gilaztdinov08:04:30

да, про , e f знаю, репл стартовать тоже изи — , ' или фигвил — ' " но SPC SPC еще короче

rustam.gilaztdinov08:04:39

так работает только через SPC m SPC или , SPC, если что как видно из set-leader-keys-for-major-mode mm — это SPC m или , может через , , забиндить? просто удобно же, как в lighttable, не надо окошко с реплом держать открытым

rustam.gilaztdinov08:04:02

да, сделал , , — работает, пока брат жив, посмотрим в процессе хоть и кастомизация есть, но таки ты привязан к cider’у — в ногу выстрелить не даст хз, хорошо это или плохо

fmnoise09:04:19

у меня такое ощущение, что конструкций кложи вполне хватает чтобы обойтись без монад

misha09:04:28

таких как some-> kappa

fmnoise09:04:28

угу, типа того

fmnoise09:04:41

хотя и есть целый algo.monads

fmnoise09:04:55

с биндом и функторами

fmnoise09:04:03

но мне кажется он для красоты там

fmnoise09:04:43

вот в скале оно имеет смысл

fmnoise09:04:43

там Maybe, который Option, прям из коробки и даже за null по рукам дают

fmnoise09:04:00

делал курс курсеровский по скале, за нул ататат сделали

misha09:04:13

кто даёт? пока идея мне красненьким не подчеркнёт - никто не "даёт"

fmnoise09:04:15

пришлось вкрутить Maybe

fmnoise09:04:34

анализатор курсеры

fmnoise09:04:46

говорят code smells

fmnoise09:04:56

because of null

misha09:04:56

пф, где продакшен, а где тот анализатор

fmnoise09:04:07

не, ну то понятно

fmnoise09:04:16

просто идеологи языка создавали этот курс

fmnoise09:04:32

собсно они видят в Maybe замену null

misha09:04:41

мне, скорее, было интересно почитать определение монадов "своими словами"

fmnoise09:04:14

я на прошлой неделе как раз делал тех.доклад на работе

fmnoise09:04:22

на тему монад

fmnoise09:04:29

правда на примере js

misha09:04:40

да в жаве тоже есть все эти мейби, но как-то, что велью на нулл проверять, что мейби.райт на нулл проверять - те же яйца

fmnoise09:04:18

ну монада Maybe позволяет без if делать цепочки вызовов

fmnoise09:04:45

при этом если где-то в цепочке проскочит null, то ничего не отвалится)

misha09:04:32

хорошо, а что такое монада? troll

fmnoise09:04:46

в русской вики неплохое определение кстати

misha09:04:56

это же не просто {:left nil :right "val"}

fmnoise09:04:03

абстракция линейной цепочки связанных вычислений

artemyarulin09:04:31

мейби это монада, но есть и другие монады

misha09:04:40

я как бы картинки все эти понимаю, а на код оно мне струдом мапится

fmnoise09:04:43

но есть брать хаскль, то там определены некие законы

fmnoise09:04:47

для монад

artemyarulin09:04:16

если у тебя все нуллабл то ты легко можешь забыть if a != null, при монадическом Maybe|Optional тебе забыть не даст компилятор

fmnoise09:04:53

ну это если язык со строгой типизацией

fmnoise09:04:36

в скале имеет смысл оно

savelichalex09:04:49

а мне кажется монады удобной абстракцией)

fmnoise09:04:54

а в кложе мне кажется some-> для майбе самое то

misha09:04:11

public class MonadApp {
	public static void main(String[] args) {
		Maybe<Integer> x = new Maybe<>(5);
		Monad<Integer> y = x.bind(v -> new Maybe<Integer>(v+1))
		                    .bind(v -> new Maybe<Integer>(v*2));
		System.out.println( ((Maybe<Integer>)y).getVal() );
	}
}
и у жавистов еще от количества скобочек в кложе припекает? ахаха

savelichalex09:04:16

а вот прям идеальное объяснение https://www.youtube.com/watch?v=ZhuHCtR3xq8

fmnoise09:04:27

кстати

fmnoise09:04:34

если очень хочется примеры от кода

fmnoise09:04:45

есть такой чувак - Брайан Лонсдорф

misha09:04:46

да я смотрел это (и не только) пару раз, не отложилось особо

fmnoise09:04:03

оно конечно специфичное сильно

fmnoise09:04:11

с ежиками и зайчиками

fmnoise09:04:44

но он именно показывает пример кода, рефакторинг в монаду или функтор, а потом уже рассказывает что это была монада

fmnoise09:04:57

но там только js

misha09:04:19

а в кложе ведь монаду рекордами никак, да? всё равно какую-то контекстную функцию писать, которой оборачивать цепочку вызова? типа (monad-context (-> x f g h))

misha09:04:14

а сделать так, чтобы x был монадой - никак?

fmnoise09:04:20

почему, у монады есть ряд ф-й обязательных

fmnoise09:04:31

их можно на протокол повесить мне кажется

fmnoise09:04:59

если мейбе например, ты вызываешь конструктор со значением

fmnoise09:04:04

получаешь коробку

fmnoise09:04:13

и на ней вызываешь мапы уже

misha09:04:18

ну чтобы код вообще от обычного кложа кода не отличался, но ты вместо стринги в x положил монаду стринговую, и хоп - все нуллпоинтеры потенциальные пропали

fmnoise09:04:13

(->Maybe x) типа такого

misha09:04:41

нууу, вот тут надо помнить, что вместо -> надо взять ->Maybe

fmnoise09:04:59

ну монады на мейбе не заканчиваются

fmnoise09:04:02

тысячи их

fmnoise09:04:22

каждая абстрагирует конкретный юз-кейс

fmnoise09:04:36

майбе - проверку на null

misha09:04:48

а хотелось бы вот так:

(let [x "foo"]  (-> x f g h))
и
(let [x (maybe "foo")]  (-> x f g h))

fmnoise09:04:52

в either можно try\catch сделать

fmnoise09:04:34

ну так делай ф-ю maybe которая будет (->Maybe x)

savelichalex09:04:35

так и надо же делать

misha09:04:39

и представь, что у тебя в let - 100 строк кода всякого, а монаду ты только в биндинге подсунул, и остальное не трогал вообще

savelichalex09:04:54

просто тебе надо на каждом шаге join ф-ю еще

savelichalex09:04:24

типа (-> x (>>= f) (>>= g))

misha09:04:08

например при вычитывании из датаскрипта оборачиваешь в 1 месте в монаду значение, и у тебя она просачивается в остальной весь проект истребляя нуллпоинтеры, вместо того, чтобы в 10 местах вспомнить, что нужно -> на ->maybe заменить

savelichalex09:04:52

по идее можно макрос конечно сделать который всегда будет join делать, а в нужной монаде нужное значение применит, так как протокол реализует

misha09:04:00

ну дык хочется же без твоего "просто подхачь каждый вызов функции в проекте"

savelichalex09:04:07

переопределить ->? 😄

fmnoise09:04:29

просачивается в остальной весь проект истребляя нуллпоинтеры - это сильно

misha09:04:42

чтобы дифф 100 строк кода был

- x "foo"
+ x (maybe "foo")
а не
- x "foo"
+ x (maybe "foo")
- (-> x f g)
+ (-> x (>>= f) (>>= g))
... ; еще 196 строк

misha09:04:47

@savelichalex ну у тебя же не весь код на рокетах (много, но не весь)

savelichalex09:04:24

да я бы вообще не стал как ты делать, как то слишком неявно все становится) я бы хотел явно монады видеть)

fmnoise09:04:56

кстати в руби так можно

fmnoise09:04:01

NilClass подхачить

fmnoise09:04:13

и все, нулпойнтеры закончились

fmnoise09:04:32

ток это, все развалится

misha09:04:39

в кложе можно extendprotocol на nil сделать тоже, но каждую ф-ю в протокол не завернешь

fmnoise09:04:51

ну в руби есть method_missing

fmnoise09:04:20

типа вызван метод, которого не знает адресат

fmnoise09:04:38

и там можно просто nil возвращать

fmnoise09:04:46

всегда

misha09:04:35

и как оно в жизни? ок? или лучше на nil проверять в итоге?

fmnoise09:04:39

не знаю, никогда не встречал на практике

fmnoise09:04:53

лучше проверять мне кажется

fmnoise09:04:21

там щас модно делать try(:method)

fmnoise09:04:43

если вызвано на nil, то вернет nil

fmnoise09:04:00

даже спец синтаксис добавили

fmnoise09:04:02

account&.owner&.address

serioga11:04:22

но компилятор не спасёт от такого:

scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)
здравствуй, NPE 🙂

artemyarulin11:04:35

ну скала язык возможностей. Там кста нельзя проще сделать = val x: Option[String] = null?

serioga11:04:53

можно 🙂

artemyarulin11:04:23

а ну вот) Хаскель няшка в этом отношении - понятия null нету вообще

serioga11:04:49

scala> val x: Option[String] = null
x: Option[String] = null

artemyarulin11:04:14

@misha ^^ вот видишь, теперь все в безопасности 😄

serioga11:04:36

т.е. типизация помогает с нуллом, но не спасает

artemyarulin11:04:15

Дак ибо Option это класс, т.е. переменная x класса Option[String], а не переменная x типа Option[String]. Т.е. val x: Int = null сделать же при всем желании нельзя

serioga11:04:20

монадические операции тебе нулл не дадут на выходе, а вот внутри Some — запросто

artemyarulin12:04:14

ну я на скале месяцек всего жил, почти ничего про нее не знаю

akond13:04:19

скажите пожалуйста что у касты на бекенде: жвм или нода?

fmnoise14:04:29

да, option помогает выразить "значение некоторого типа или null", но от кривых рук не спасает

mike_ananev15:04:34

народ, требуется архитектор (навыки backend и фронт енд) стек datomic +(clojure back) + clojurescript (front). кому интересно в личку плиз

mike_ananev15:04:08

в москве

niquola18:04:08

Кто как с формочками воюет?

andre18:04:48

а что с ними воевать?

kishanov19:04:54

мы сделали DSL но так и не выложили в опенсурс как я обещал (завал на работе)

kishanov19:04:57

(def fields
  {::model/range
   (f/map->Field
     {:label      "Range"
      :validators [(validators/spec ::model/range model/invalid-asn-range-message)]})})


(def crud-form
  (f/map->Form
    {:label  "ASN Pool"
     :flags  {:disabled?               false
              :show-validation-errors? false}
     :fields {:display_name (f/map->Field {:blueprint-field ::common/display_name})
              :ranges       (f/map->Form {:blueprint-form ::model/ranges})
              :status       (f/map->Field {:label "Status"})
              :tags         (f/map->Field {:blueprint-field ::common/tags})}}))


(def forms
  {::model/details-payload
   crud-form

   ::model/create-payload
   (update crud-form :fields dissoc :status)

   ::model/ranges
   (f/map->Form
     {:label     "Ranges"
      :required? true
      :fields    [(f/map->Field {:blueprint-field ::model/range})]
      ; TODO: check for overlapping ranges
      ;:validators []
      :subforms  {:add-range-form (f/map->Form
                                    {:blueprint-form ::add-range-form
                                     :flags          {:show-validation-errors? false}
                                     :on-submit      :parent-fields-conj})}})
   ::add-range-form
   (f/map->Form
     {:label      "Add Range"
      :validators [(validators/generic model/first-less-than-last? "First should be less than Last")]
      :fields     {:first (f/map->Field
                            {:blueprint-field ::common/asn
                             :required?       true
                             :label           "First"})
                   :last  (f/map->Field
                            {:blueprint-field ::common/asn
                             :required?       true
                             :label           "Last"})}})})

kishanov19:04:16

дефайнишь форму со всякими свистелками и перделками

kishanov19:04:10

для либы есть биндинги в re-frame - собсно как инициализировать по этой схеме, как диспатчить одно поле

kishanov19:04:53

после этого можно делать биндинги на разные UI либы, типа как у нас на semantic-ui

(defn generic-input-field
  [field & [{:keys [input-type coerce-fn suppress-label? style attrs] :as options}]]
  (let [read-only? (if (contains? options :read-only?)
                     (:read-only? options)
                     (forms/flag field :read-only?))]

    [:div {:class (field-class field options)}

     (when (not suppress-label?)
       [label field])


     [:div
      [:input (merge
                attrs
                {:style       style
                 :type        input-type
                 :value       (str (:value field))
                 :placeholder (str (:placeholder field))
                 :read-only   read-only?
                 :on-change   (forms/on-submit-fn field {:coerce-fn coerce-fn})})]]

     (when-not (:suppress-validation-errors? options)
       [validation-errors field options])]))

kishanov19:04:05

Последние веяния - определять payload который должна сделать форма через clojure.spec, на каждый on-change на форме прогонять s/explain-data, парсить выхлоп и через subscription просовывать его в форму по полям (какие valid/не valid, какие disabled и т.д.)

misha19:04:23

(get options :read-only? (forms/flag field :read-only?))

kishanov19:04:04

это в одном месте я хак втыкал, потому что у нас в одном из response’ов от бэкэнда была семантическая дыра

misha19:04:32

(when-not suppress-label? ...)

misha19:04:06

вон даже ниже веннот opieop

kishanov19:04:09

суть не в этом. Начальный подход был иметь мапу которая описывает все формы как композицию полей и иметь dispatch’и b sub’ы на поля и на форму.

misha19:04:36

туда бы и спеку сразу, или даже со спеки и начать

kishanov19:04:37

@misha ты прав, мы говнокодеры. я просто отвечаю на вопрос “кто как с формами воюет”

kishanov19:04:50

мы это делали 2.5 года назад, сейчас портируем на спеку

misha19:04:56

та то понятно, набросил просто

kishanov19:04:31

на, потешь свои “говнокод-детектив” скиллы, это обертка над semantic’овским search-field’ом с автокомплитом и малтиселектом

kishanov19:04:55

ну или не выпендривайся и предложи лучше 🙂

misha19:04:47

25 строк копипасты!

kishanov19:04:37

красава, глаз-алмаз

misha19:04:26

ну типа в функцию положить и 2 раза вызвать opieop

misha19:04:55

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

misha19:04:12

разве что спеку туда еще добавить

misha19:04:29

@nicola может ты чего-то другого ожидал? расскажи

rmuslimov20:04:55

сорри за оффтоп, наверняка кто-то бывал на рит++ ранее. Достойное мероприятие? стоит двух проведенных там дней? http://ritfest.ru/

rmuslimov20:04:06

я смотрю на бекенд сессию в этом году и не могу понять надо или нет

dragoncube20:04:30

@misha а где там 25 строк копипасты то?

dragoncube20:04:03

@nicola а насколько у тебя формы однородные?

misha21:04:10

@dragoncube ты шутишь?

dragoncube21:04:40

@misha а, ты про complex-select-field ?