В отличие от Java, Scala позволяет наследоваться от Enumeration. Что упрощает дело в некоторых случаях. Плюс еще есть case classes, что даёт еще больше простора для маневров.. Чувствую, то, что я уже второй день пытаюсь красиво сделать на Java, на Scala выйдет быстро и элегантно.
Показаны сообщения с ярлыком scala. Показать все сообщения
Показаны сообщения с ярлыком scala. Показать все сообщения
пятница, 11 июня 2010 г.
пятница, 2 апреля 2010 г.
Хороший, годный блог про Scala
Недавно нашел http://daily-scala.blogspot.com. Крайне рекомендуется к прочтению всем заинтересованным лицам :))
воскресенье, 21 марта 2010 г.
Scala+Spring
Сегодня решил попробовать, как Scala дружит со Spring. Скачал крайнюю версию (3.0.1) , решил попробовать нововведение - JavaConfig. Теперь можно всё конфигурировать прямо в коде, как в Google Guice. Был приятно удивлён - оно просто работает. Никаких танцев с бубном, завелось всё с первого раза. Ещё один аргумент переходить на Scala. В следующий раз попробую прикрутить Hibernate. Очень меня привлекает возможность использования traits в доменной модели - должно хорошо уменьшить дублирование.
воскресенье, 28 февраля 2010 г.
[Scala] By-name parameters
Вспомнил пароль к профильному блогу по программированию, перенес прошлую статью по Scala туда и добавил еще одну - тема в заголовке.
пятница, 26 февраля 2010 г.
[Scala] Function currying
Вот эта тема меня поначалу сильно озадачила :) Что это такое, в принципе было понятно, не было понятно - а зачем оно мне надо? Итак, каррирование a.k.a function currying - что это? Если у нас есть некая функция с несколькими аргументами, то для получения ее значения нам необходимо передать ей значения всех аргументов. При применении каррирования мы можем передать ей лишь некоторые из них, а в качестве результата получим функцию, принимающую оставшиеся аргументы. И если уже в эту функцию мы передадим остальные аргументы, то получим собственно результат. Названа техника в честь ее изобретателя, Хаскелла Карри. В некоторых случаях это позволяет уменьшить дублирование кода и упростить его переиспользование.
В качестве практического примера позаимствую хороший пример с вычислением налогов, желающие могут ознакомиться с оригиналом на аглицком здесь.
Итак, у нас есть несколько штатов, в которых есть города. В каждом городе существует своя политика налогообложения, где сумма облагается налогом по одной ставке и плюс к этому, определенная ее часть облагается дополнительным налогом по другой ставке:
| Abbr. | State | City | Tax computation |
| TF | Terrafirma | n/a | 2% of the entire value |
| TC | Terracotta | n/a | 6% on the first $1500 |
| CF | Confusion | Gotham | 5% on the entire value plus 4.5% on the first $1000 |
| CF | Confusion | Ocean City | 5% on the entire value plus 3% on the first $1000 |
| CF | Confusion | Hometown | 5% on the entire value plus 1.5% on the first $1000 |
Сначала определим обобщенную функцию вычисления налогов:
def pct(rate: Double, amt: Long) = (rate * amt / 100.0D + 0.5D).toLong //helper function for rounded percentage calculation
def tax(rateA: Double, limit: Long, rateB: Double, amt: Long) = pct (rateA, amt) + pct (rateB, limit min amt)
Теперь определим функции для вычисления налогов в каждом городе без применения каррирования:
def taxTF (amt: Long) = tax(2.0D, 0, 0.0D, amt)
def taxTC (amt: Long) = tax(0.0D, 150000, 6.0D, amt)
def taxGothamCF (amt: Long) = tax(5.0D, 100000, 4.5D, amt)
def taxOceanCityCF (amt: Long) = tax(5.0D, 100000, 3.0D, amt)
def taxHometownCF (amt: Long) = tax(5.0D, 100000, 1.5D, amt)
Дублирование видно сразу - передаются одинаковые аргументы сразу в нескольких местах. К тому же этот код не очень хорошо читаем, сразу и не понятно, что к чему относится. А теперь добавим карри. Общая функция вычисления налогов станет выглядеть так:
def tax = (rateA: Double) => (limit: Long) =>
(rateB: Double) => (amt: Long) =>
pct (rateA, amt) + pct (rateB, limit min amt)
Первые 2 функции вычисления налогов примут вид:
def taxTF = tax( 2.0D)(0)(0.0D)
def taxTC = tax( 0.0D)(150000)(6.0D)
Здесь мы уже отделили мух от котлет - константы передаются в общую функцию, которая вернет нам функцию с одним аргументом. Вроде бы не особо на первый взгляд и необходимая вещь, однако это позволяет писать более структурированный код, где функции будут более специализированы. С остальными тремя все еще интереснее - там первые 2 аргумента дублируются, т.к. для штата процентные ставки и суммы одинаковы. Опрделим функцию налогообложения на уровне штата:
def taxCF = tax(5.0D)(100000)
Теперь черз нее можно выразить города:
def taxGothamCF = taxCF(4.5D)
def taxOceanCityCF = taxCF(3.5D)
def taxHomeTownCF = taxCF(1.0D)
Для города Gotham налог будет таким:
scala> taxGothamCF(9999)
res0: Long = 950
Дублирования нет, каждая функция делает только то, что от нее требуется. Использовать можно например так - определим функцию отчетности:
def report(taxf: (Long => Long), amts: List[Long]) = {
println("Tax on " + amts + " is " + taxf((amts :\ 0L)(_ + _)))
}
val items = List[Long](20000, 40000, 60000, 80000)
scala> report(taxHomeTownCF, items)
Tax on List(20000, 40000, 60000, 80000) is 11000
Что это даёт? В краткосрочной перспективе вобщем-то особенно ничего, но если нужно обеспечить гибкую функциональность, когда требования меняются часто, и нужно быстро и легко вносить изменения в код - то этот приём будет однозначно полезен. Кстати, налогообложение - как раз такая предметная область. Ставки и формулы там меняются весьма часто.
четверг, 25 февраля 2010 г.
Еще о Scala
Краткость - сестра таланта. А программист - ленивое существо :) За что мне понравилась Scala - так это за краткость. Вот если посмотреть на примере - надо посчитать норму вектора. Для тех, кто уже забыл, что это такое - корень из суммы квадратов всех его координат. Пускай вектор у нас представлен списком, каждый элемент которого - соответствующая координата. Ниже 2 реализации - на Java и на Scala:
Java
List<Double> vector = new ArrayList<Double>();
vector.add(-1.0);
vector.add(2.0);
vector.add(3.0);
Double norm = 0.0;
for (Double coord : vector) {
norm+=coord*coord;
}
norm = Math.pow(norm, 0.5);
Scala
val v = -1.0::2.0::3.0::Nil
val norm = Math.sqrt((0.0 /: v)((x, y) => x + y * y))
Разница в обьёмах набранных буков очевидна :) А результат один - корень из 14.
Подписаться на:
Сообщения (Atom)
