metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2012-11-06 04:15 am
Entry tags:

Scala

Читаю книжку Одерского, до основной шизы еще не добрался, но такое ощущение, что в скале чрезмерно много синтаксического сахара. Типа "тут вы можете скобки опустить, а тут вместо скобок использовать фигурные скобки, а тут мы прямо в параметрах класса сделаем их полями, а в multiline string literal вы можете сделать отступ и stripMargin" и прочая и прочая в том же духе.
Основное из этого, видимо - function literals и вызов методов в стиле a methodName b, без точек и скобок, что делает код более лаконичным, одновременно позволяя при желании превратить код в нечитабельный ад.

Заодно по наводке [livejournal.com profile] jdevelop глянул на http://spray.io/ https://github.com/spray/spray/wiki
Примеры там, конечно, знатный abuse возможностей языка и вычислений на типах, типа extraction-директив с HList в качестве параметра типа.

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

PS: Вот, к примеру:
https://github.com/spray/spray/blob/master/docs/documentation/spray-routing/code/docs/HttpServiceExamplesSpec.scala

В SimpleService HttpResponse реализован как html-код написанный прямо внутри скала-кода. Сижу уже 30 минут ищу, где это преобразование реализовано и как. Т.е. не видя отдельных литералов и их типов (которые без загрузки всего оного кода с зависимостями в IDE/интерпретатор еще и не увидишь), с ходу догадаться, что происходит, достаточно сложно. XML literals, встроенные в язык и где-то implicit для конверсии.

PPS: implicit evidence:
http://jim-mcbeath.blogspot.com/2008/11/scala-type-infix-operators.html
http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented

По-моему, это уже достаточно сложно, чтобы увлечь психов и стать новыми крестиками. Вот [livejournal.com profile] xeno_by еще приделает макросы - и совсем хорошо станет.

[identity profile] golikov konstantine (from livejournal.com) 2012-11-06 06:10 pm (UTC)(link)
А что в эрланговском паттерн матчинге есть, чего нет в скаловском?

мне в голову приходит только паттерн матчинг в аргументах функции, но а) это в некотором виде существует в виде structural typing б) синтаксический сахар и аналог без сахара в скале есть

[identity profile] divine-assass1n.livejournal.com 2012-11-06 06:21 pm (UTC)(link)
Да, в аргументах функции, плюс, как тут рядом в треде уже развернули дискуссию на эту же тему "многабукаф".

Guards опять же.

Вот например решение простого задания из курса Мартина на coursera, первая неделя, на сбалансированные круглые скобки, только на эрланге:

-module (balance).

-export([balance/1]).

balance(CharList) -> balance(0, CharList).

balance(-1, _) -> false;
balance(0, []) -> true;
balance(_, []) -> false;
balance(Counter, [$(|T]) -> balance(Counter + 1, T);
balance(Counter, [$)|T]) -> balance(Counter - 1, T);
balance(Counter, [_|T]) -> balance(Counter, T).

imho, элегантно и очень читабельно.

Вообще, я не претендую ни на что больше чем субъективное мнение, мой скромный опыт в скале - это почти завершенный курс Мартина на coursera c его assignments и 150 страниц книги. И мнение меняется по мере изучения предмета.

[identity profile] golikov konstantine (from livejournal.com) 2012-11-06 06:30 pm (UTC)(link)
Guards есть http://metaclass.livejournal.com/741714.html?thread=14887506#t14887506

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

Вот например сбалансированные строки на скале

def isBalanced(list: List[Char]) = {
@annotation.tailrec
def countBracets(string: List[Char], count: Int = 0): Int = {
string match {
case '('::tail => countBracets(tail, count+1)
case ')'::tail => countBracets(tail, count-1)
case x::tail => countBracets(tail, count) // just skip if not bracet
case Nil => count
}
}

if (countBracets(list) == 0) true else false
}

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

[identity profile] divine-assass1n.livejournal.com 2012-11-06 06:38 pm (UTC)(link)
Ну что я могу сказать? Мне скала нравится. Когда начинал, не ожидал, что понравится.

[identity profile] thesz.livejournal.com 2012-11-06 09:13 pm (UTC)(link)
weight '(' = 1
weight ')' = -1
weight x = 0
balanced = check . scanl (+) 0 . map weight
    where
        check balances = all (>=0) balances && last balances == 0
Не мог удержаться. ;)

[identity profile] metaclass.livejournal.com 2012-11-06 09:22 pm (UTC)(link)
Ну вот зачем вы издеваетесь над людьми своим лаконичным хаскелем? :)
После скалы это выглядит как бальзам на душу.

[identity profile] thesz.livejournal.com 2012-11-06 09:28 pm (UTC)(link)
Мне можно. Я уже давно потерян для программистского общества. ;)

Это ещё и демонстрация, чем выгодна ленивость. В качестве бонуса. ;)

[identity profile] golikov konstantine (from livejournal.com) 2012-11-06 10:45 pm (UTC)(link)
плюсую
и вправду красиво и компактно

[identity profile] andy legkiy (from livejournal.com) 2012-11-06 11:19 pm (UTC)(link)
Сравнивают конкретный пример с рекурсией, так надо обязательно выставить HOF. Будто их больше нигде нет.
def balanced(seq: Seq[Char]) = {
  val balances = seq.view.map {
    case '(' => 1
    case ')' => -1
    case _ => 0}.scanLeft(0)(_+_)
  balances.forall(_ >= 0) && (balances.last == 0)
}

[identity profile] thesz.livejournal.com 2012-11-07 08:23 am (UTC)(link)
Есть. Но не столь краткие и не так хорошо разделяют обязанности.

[identity profile] xeno-by.livejournal.com 2012-11-07 08:37 am (UTC)(link)
Разделяют обязанности?

[identity profile] thesz.livejournal.com 2012-11-07 08:52 am (UTC)(link)
Да. Separation of concerns. Не переводить же эту фразу, как "разделение беспокойств" или "разделение интересов".

[identity profile] xeno-by.livejournal.com 2012-11-07 09:00 am (UTC)(link)
Я скорее хотел узнать в чем проявляется лучшее разделение обязанностей.

[identity profile] thesz.livejournal.com 2012-11-07 09:33 am (UTC)(link)
В ленивости?

Как я понимаю, short circuit оператор && наверняка встроен в Scala.

[identity profile] xeno-by.livejournal.com 2012-11-07 09:46 am (UTC)(link)
Понятно.

Оператор пока еще да, встроен.

[identity profile] thesz.livejournal.com 2012-11-07 10:01 am (UTC)(link)
Вот-вот. И сейчас вы накрутите ещё всякого. ;)

[identity profile] isorecursive.livejournal.com 2012-11-07 10:07 am (UTC)(link)
Наверное, встроен, для эффективности, но можно сделать и средствами языка:
http://www.scalakata.com/509a323ce4b093f3524f38fa
Но, конечно, это by-name, а не by-need.

[identity profile] thesz.livejournal.com 2012-11-07 10:32 am (UTC)(link)
Вы определение && на Хаскеле видели?

И как я понимаю, булевский тип тоже встроен.

[identity profile] isorecursive.livejournal.com 2012-11-07 10:45 am (UTC)(link)
Что-нибудь такое ?:
True && True = True
_    && _    = False

Дело в том, что паттерн-матчинг в хаскеле дешугарится в case, а это такой же встроенный примитив, как и if.

@ И как я понимаю, булевский тип тоже встроен.
Ну это всё мелочи, по-моему. Можно вот так:
http://www.scalakata.com/509a3b5ce4b093f3524f38fd
и так:
http://www.scalakata.com/509a3bb3e4b093f3524f38ff
Edited 2012-11-07 10:46 (UTC)

[identity profile] thesz.livejournal.com 2012-11-07 11:22 am (UTC)(link)
Нет, не такое. Ваш оператор не будет short circuit. В частности, для False && error "Badam!" будет вычислен error "Badam!"

True && x = x
False && _ = False

Видите ли, в чём дело. Я могу 1) сделать свой собственный if и 2) воспользоваться кодированием конструкторов и деструкторов (сравнение с образцом) через функции. Это так называемое кодирование Чёрча.

Если вы не знали, то вот вам пример (я уж задолбался его приводить):
*Main> let true = \a b -> a
*Main> let false = \a b -> b
*Main> let a &&& b = a b false
*Main> let ifThenElse c a b = c a b
*Main> ifThenElse (true &&& false) 10 12
12
*Main> ifThenElse (true &&& true) 10 12
10
*Main> ifThenElse (true &&& true) 10 (error "Badam!")
10
*Main> ifThenElse (false &&& error "Badam!") 10 12
12

Попробуйте сделать такое на Scala.

На таком кодировании основана AwesomePrelude - как можно взять практически обычный Хаскель (пара расширений) и скомпилировать его в JS библиотекой. Без макросов. Без трансляции, как у меня в HHDL. Простой библиотекой.

Short-circuit операторы я могу также сделать и для других значений. Например, для Q Bool, если сочту это нужным. Поэтому я и обратил ваше внимание на встроенность bool.

(no subject)

[identity profile] xeno-by.livejournal.com - 2012-11-07 12:36 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 13:54 (UTC) - Expand

(no subject)

[identity profile] xeno-by.livejournal.com - 2012-11-07 12:38 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 13:53 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2012-11-07 14:12 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 14:29 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 16:09 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 19:10 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-07 19:47 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-09 04:20 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-09 09:25 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-10 09:37 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-10 10:45 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-11 00:57 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 01:23 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-11 03:10 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 10:04 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-11 03:31 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 10:18 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-12 05:47 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-12 06:27 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-12 08:55 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-12 09:00 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-12 11:46 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-12 19:25 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-13 02:23 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-13 04:19 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-14 03:46 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-14 08:21 (UTC) - Expand

(no subject)

(Anonymous) - 2012-11-15 04:46 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-15 10:21 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-15 12:21 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-15 20:44 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-16 02:12 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-16 08:31 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-16 09:54 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-16 11:00 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-16 11:36 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-16 13:08 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-16 13:45 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-16 17:47 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-17 03:41 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-17 04:05 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-17 07:18 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-17 18:01 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-18 04:03 (UTC) - Expand

(no subject)

[identity profile] migmit.livejournal.com - 2012-11-18 11:11 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-25 12:53 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-13 10:20 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-14 03:49 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-14 08:29 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-15 04:54 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-15 08:53 (UTC) - Expand

(no subject)

[identity profile] berezovsky.livejournal.com - 2012-11-15 09:16 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-15 10:54 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-15 12:01 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-11 03:38 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 01:29 (UTC) - Expand

(no subject)

[identity profile] valentin budaev - 2012-11-11 03:01 (UTC) - Expand

[identity profile] metaclass.livejournal.com 2012-11-07 10:34 am (UTC)(link)
А что будет, если есть два импортированных класса с операторами &&& и implicit-конверсией - какой из них используется в этом случае?

[identity profile] isorecursive.livejournal.com 2012-11-07 11:02 am (UTC)(link)
Если подходит первый (по типами и сигнатуре), то он, если нет - будет попытка использовать конверсию.
И это, наверное, самый сложный и хитрый момент в имплицитных конверсиях. По мне, лучше воздерживаться от них, и использовать только обогащения (новые implicit class, но их пока нет на scalakata), и только такие, которые не создают конфликтов имён.
И самое плохое в имплицитных конверсиях, что люди думают, будто имплицитные значения (type-directed скоупинг) - что-то близкое по духу, и тоже стрёмное.

[identity profile] xeno-by.livejournal.com 2012-11-07 11:31 am (UTC)(link)
+1 про implicit vals

[identity profile] xeno-by.livejournal.com 2012-11-07 11:31 am (UTC)(link)
Если подходят оба, будет ошибка компиляции.

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 01:34 (UTC) - Expand

(no subject)

[identity profile] xeno-by.livejournal.com - 2012-11-11 08:25 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 10:09 (UTC) - Expand

(no subject)

[identity profile] xeno-by.livejournal.com - 2012-11-11 10:12 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-11 11:04 (UTC) - Expand

[identity profile] thesz.livejournal.com 2012-11-06 09:30 pm (UTC)(link)
Кстати, у вас код пропустит строку ")(". Код на Эрланге и мой не пропустят.

Мелочь, а приятно. ;)