Search
Write a publication
Pull to refresh
0
0
igorkarp @igorkarp

User

Send message
Посмотрел я на приведенный JS код, на то как все в одну кучу смешано, как ошибки во входной строке не обрабатываются, как выражения не оптимизируются. И, в основном с целью с parser combinators поиграться, переписал на Scala. Мухи получились отдельно, котлеты отдельно, потом еще оптимизацию прикрутил.

2-ая задача (Scala)
import scala.util.parsing.combinator._
import scala.util.parsing.input.CharSequenceReader

sealed abstract trait Expr {
  def allStrings: List[String]
  def isLiteral = false
  def isEmpty = false
}
case class Literal(s: String) extends Expr {
  override def allStrings: List[String] = List(s)
  override def isLiteral = true
}
case object Empty extends Expr {
  override def allStrings: List[String] = Nil
  override def isEmpty = true
}
case class Multi(es: List[Expr]) extends Expr {
  override def allStrings: List[String] = es.flatMap(_.allStrings)
}
case class Concat(es: List[Expr]) extends Expr {
  override def allStrings: List[String] = allStrings(List(""), es)

  private def allStrings(prefixes: List[String], es: List[Expr]): List[String] = es match {
    case Nil => prefixes
    case h :: t => allStrings(for (p <- prefixes; s <- h.allStrings) yield p + s, t)
  }
}

trait ExprParsers extends RegexParsers {
  override val skipWhitespace = false

  def literal: Parser[Literal] = """[^{|}]+""".r ^^ { Literal(_) }
  def multi: Parser[Multi] = "{" ~> repsep(cexpr, "|") <~ "}" ^^ { l => Multi(l.distinct) }
  def concat: Parser[Concat] = (mexpr +) ^^ { Concat(_) }
  def cexpr: Parser[Expr] = concat
  def mexpr: Parser[Expr] = literal | multi
}

trait ExprOptParsers extends ExprParsers {
  override def cexpr: Parser[Expr] = super.cexpr ^^ { _ match {
    case Concat(List(x)) => x
    case Concat(l) if l.forall(_.isLiteral) => Literal(l.map(_ match {case Literal(t) => t}).mkString)
    case Concat(l) if l.exists(_.isEmpty) => Empty
    case x => x
  }}
  override def mexpr: Parser[Expr] = super.mexpr ^^ { _ match {
    case Multi(Nil) => Empty
    case Multi(List(x)) => x
    case Multi(l) if l.exists(_.isEmpty) => Empty
    case x => x
  }}
}

object Parser extends ExprOptParsers {
  private lazy val main: Parser[Expr] = phrase(cexpr)
  private def parse(s: String): Expr = main(new CharSequenceReader(s)) match {
    case Success(e, _) => e
    case NoSuccess(m, n) => throw new IllegalArgumentException("Parsing error at " + n.pos + "\n" +
        n.pos.longString + ": " + m)
  }

  def printAll(s: String): Unit = {
    val p = parse(s)
    println(p.allStrings.mkString("\n"))
    println(p)
  }

  def shouldFail(s: String): Unit = {
    try {
      val p = parse(s)
    } catch {
      case e: IllegalArgumentException => println(e.getMessage)
    }
  }

  def main(args: Array[String]): Unit = {
    shouldFail("{")
    shouldFail("}")
    shouldFail("")
    printAll("тест")
    printAll("тест {тест}")
    printAll("{тест} {тест}")
    printAll("{тест {тест}}")
    printAll("{}")
    printAll("{{{{{{{{{{тест {тест}}}}}}}}}}}")
    printAll("{A | B | C} тест")
    printAll("{A | B} {A | B}")
    printAll("{A |A | B} {A | B| B}")
    printAll("{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро|мгновенно} случайным образом|менялось каждый раз}.")
    printAll("{Пожалуйста|Просто} сделайте так, чтобы это {удивительное|крутое|простое} тестовое предложение {изменялось {быстро{}|мгновенно} случайным образом|менялось каждый раз}.")
  }
}

Упомичая Тьюринга невозможно не вспомнить и Алонзо Чёрча. Его работы появились несколько ранее работ Тьюринга, а лямбда-исчисление все же более «удобный» формализм чем машина Тьюринга.
Перед тем как Хабр превратится в Трибуну УФН позволю себе процититовать:
«If I ever design a programming language, I will name it Neutrino, so I can claim it is faster than C.»
Есть такая фраза 'Past Performance Does Not Guarantee Future Results' и по моему сугубо личному мнению, на ворпос о прошлой работе тратить более 5 минут бесполезно. Во время интервъю надо выяснить принесет ли он пользу на новом месте (что знает, что умеет) и подходит ли он команде и компании.

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

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

Вопросы про разработку архитектуры приложения, системы или сервиса спрашиваю только достаточно толковых/опытных. С остальными это как правило выброшенное время, да и с более слабыми кандидатами на это редко хватает отведенного на интервъю времени.
А до этого чем компилировали, если Eclipse, то последний раз когда я его использовал там версия scalac была 2.7.7, в 0.3.312 — 2.8 пререлиз. 2.8 не полностью совместим с 2.7. Ну и пререлиз само собой подразумевает прекачество.

Если охота покапаться можно попробовать с командной строки 2.8 скомпилировать. Если неохота, и проект открытый могу и сам покопаться.

Ну а вообще YMMV как говорится :),
Субъективно стало лучше, например, по двойному ctrl+space видны недоступные методы. Специфически Scala плагин часто огрубляет дополнение при наличии ошибок. Видимо свой парсер не такой устойчивый/продвинутый как для Java, и пока scalac typer не вычислит все типы, предлагает только методы класса Object.
scalac когда компилирует занемяет пунктуацию в именах на мнемонику, = на $eq, + на $plus, — на $minus и т.д.

Например, если в Scala имеется класс

package test

class Test {
  def test_=(s: String) = println(s)
}

То в Java к test_= методу можно доступится следующим образом:

package test;

import java.lang.reflect.Method;

public class Main {

  public static void main(String[] args) throws Exception {
    Method m = Class.forName("test.Test").getMethod("test_$eq", String.class);
    
    m.invoke(new Test(), new Object[] {"scala"});
  }
}

ну или если reflection не нужен то:

package test;

public class Main {

  public static void main(String[] args) throws Exception {
    new Test() {
      public void callScala(String s) {
        test_$eq(s);
      }
    }.callScala("java");
  }
}
Ставим IntelliJ IDEA Comunity edition и Scala плагин, например 0.3.312.
Или Scala for Netbeans или как уже упоминали Eclipse с плагином.

Я использовал все три, дольше всего Eclipse, для Netbeans плагин совсем не понравился — сыроват еще, но в последнее время пересел на IDEA. Для тех кому все равно какое IDE использовать посоветовал бы IDEA, но и в Eclipse поддержка Scala вполне достойная.
igorkarp *at* yahoo.com

Заранее спасибо.
А пример можете привести где javac этого не делает?
Даже если параметр используется, но только внутри метода, т.е. не присваивается полю класса и не передается другим методам в качестве параметра, память может быть освобождена.
Вцелом статья неплохая.
Помните, каждая строка — неизменяемый объект.
Делая так: String x = «ads» + «dsada»; вы сжираете не 8*2 а 16*2 байт. Сначала происходит создание первых двух строк, затем третьей.

Строго говоря это неправда. Javac (компилятор Java) осуществляет т.н. свертку постоянных (constant folding).

String x = "ads" + "dsada"; эквивалентно String x = "adsdsada";


Чтобы избежать этого были придуманы StringBuffer и StringBuilder. Если вам нужно строить длинные строки — используйте эти штуки. Они быстрее и менее требовательны к памяти (так как не копируют строки), а StringBuffer ещё и потоко-безопасен (зато чуть больше тормозит).
Пример:

StringBuilder hi = new StringBuilder;
hi.append(«Привет, мир»);
hi.append(". ");
hi.append(«Как твои дела?»);
System.out.println(hi.toString());

Во-первых append копирует аргумент а toString создает копию строки.
Во-вторых приведенный код менее эффективен чем System.out.println(«Привет, мир» + ". " + «Как твои дела?»);
Ну а в-третьих, даже если производится конкатенация переменных строк а не постоянных, вместо:

void f(String var1, String var2, String var3) {
  System.out.println(var1 + var2 +var3);
}

javac генерирует байт-код эквивалентный:

void f(String var1, String var2, String var3) {
  StringBuilded sb = new StringBuilder();
  ab.append(var1);
  ab.append(var2);
  ab.append(var3);
  System.out.println(sb.toString());
}

Так что не бойтесь использовать + со строками.
Присоединяюсь к мнению bishop3000, с единственной разницей: на первое место я бы поставил Working Effectively with Legacy Code
вот только эта пустота и содержит все :-)
SUM(1/к) от 1 до n действително ассимтотически LN(н).

Но решавшими не учтен релативистский еффект! всем думать еше 2 часа
первая переведена, но весьма отвратно ;-(
Я когда начинал с XSLT работать учился по "XSLT: Programmer's Reference by Michael Kay". Для тех кто с версией 1.0 работает наверно до сих пор ничего лучше нет. Версия 2.0 имхо лучше всего описана у него же в других двух книгах: XSLT 2.0 Programmer's Reference & XPath 2.0 Programmer's Reference.

Information

Rating
Does not participate
Registered
Activity