Знаете ли вы, что
Scala - это Haskell в жабьей шкуре?
Если кложура сразу видна как лисп и не совсем мейнстримный язык, то скала замаскирована жабьей шкуркой от зоркого ока менеджеров, чтобы к тому времени, как до них дойдет, во что они вляпались - было уже поздно.
Язык знатно безумный, я почти Programming in Scala дочитал. И кое-какие вещи там сильно похожи на решение некоторых проблем с наследованием и зависимостями типов друг от друга, которых мне не хватало в дельфи и дотнетах :)
Если кложура сразу видна как лисп и не совсем мейнстримный язык, то скала замаскирована жабьей шкуркой от зоркого ока менеджеров, чтобы к тому времени, как до них дойдет, во что они вляпались - было уже поздно.
Язык знатно безумный, я почти Programming in Scala дочитал. И кое-какие вещи там сильно похожи на решение некоторых проблем с наследованием и зависимостями типов друг от друга, которых мне не хватало в дельфи и дотнетах :)
no subject
no subject
no subject
no subject
Так и получается ... where f ... = ...; g ... = ... и т.д., ведь осмысленные имена не всегда придумываются, и не всегда есть время и желание думать над именованием каждого фунарга.
no subject
no subject
no subject
no subject
макросы нужны не только для тех вещей, которые можно было встроить в компилятор, и даже для этих, я думаю,
решение с их использованием может быть (например, если в компиляторе это всё делалось отдельными фазами, или плагинами, опирающимися на их порядок, и вынужденными думать, как не испортить при обработке предположения о коде следующей фазы и т.д.) существенно выигрышнее, чем реализация того же в компиляторе. То есть, макросы можно рассматривать и как модульные расширения компилятора, абстрагированные до уровня кода. Я слышал, что некоторые вещественные доказательства такой выигрышности уже есть, и знаю, что ещё несколько находятся в процессе разработки. Из юзкейсов макросов, которые вообще никак не могли быть учтены в хост-языке, наиболее очевидные - пользовательские оптимизации и вложения разной глубины подъязыков, всяческих логик и систем типов. Вкладываемость только на очень-очень поверхностном и стартовом уровне захватывается всякими RebindableSyntax.
no subject
no subject
В другом есть планы поэкспериментировать с развязанными модульными вложениями statement-абстракторов аля do и proc и вообще подъязыков, когда разберусь с тем, как там всё оттипизировать.
no subject
no subject
(см. Мифический Человеко-Месяц)
no subject
В данном случае это значило, что несколько макросов я написал чтобы прощупать некоторые аспекты,
а ещё пару - для проекта, который заключается в том, чтобы заменить компиляторный плагин решением на макросах.
no subject
no subject
по описанному в вики закону: замена готового и работающего на альтернативное, но лучшее - это всё-таки другое.
no subject
Если вам требуется метапрограммирование, то ваш инструмент слишком низкого уровня.
no subject
Кстати, если "мета" понимать в более общем смысле, например, как в понятии "метаматематика" или "металогика", то, например, всякие паттерны вроде функторов и монад - тоже вполне метапрограммирование. Просто не символьное а структурное.
no subject
no subject
Там в 3.1 наглядно показано, что можно, конечно, просто монадки звать из do/for-нотации, но это настолько неудобно, что проще будет не использовать это совсем.
А что касается EDSL, в хаскеле даже лямбда-абстракцию и аппликацию не перегрузить через RebindableSyntax, так что подъязыки с кастомными биндерами неповкладывать. Что уж говорить о кастомных подсистемах типов.
Может быть, эти EDSL были не совсем подъязыками, а скорее библиотеками комбинаторов?
no subject
Я не знаю, зачем нужны delimited continuation. Если вы мне скажете, зачем они мне нужны, я сделаю.
> в хаскеле даже лямбда-абстракцию и аппликацию не перегрузить через RebindableSyntax,
Типы классов.
class Q a
instance Q This
instance Q That
instance (GG a, Q b) => Q (a -> b)
>Может быть, эти EDSL были не совсем подъязыками, а скорее библиотеками комбинаторов?
В чем разница?
no subject
А Вы в раздел 4 загляните - он практическому применению посвящён.
Особенно обратите внимание на 4.2 - это как-раз то, о чём я говорил в http://metaclass.livejournal.com/763675.html?thread=15938075#t15938075
@ Типы классов.
А как они помогут пронаблюдать имя переменной лямбды и имена свободных термов? А без этого произвольный биндер подъязыка на выразишь.
Вот, смотрите:
object Sublang { abstract sealed class Term[T] type ~>[A, B] = Term[A => B] case class Num(x: Double) extends Term[Double] case class Sum(a: Term[Double], b: Term[Double]) extends Term[Double] case class Var[T](name: String) extends Term[T] case class Abs[A, B](arg: Term[A], body: Term[B]) extends (A ~> B) case class App[A, B](fun: A ~> B, arg: A) extends Term[B] object embeddings { def embedLit(c: Context)(x: c.Expr[Double]): c.Expr[Term[Double]] = { import c.universe._ x.tree match { case Ident(name) => reify { Var[Double](c.literal(name.decoded).splice) } case Literal(Constant(x: Double)) => reify { Num(c.literal(x).splice) } } } def embedVars(c: Context)(tree: c.Tree): c.Tree = { import c.universe.{treeCopy => tc, _} tree match { case Apply(fun, args) => tc.Apply(tree, embedVars(c)(fun), args.map{embedVars(c)(_)}) case Ident(name) => reify { Var(c.literal(name.decoded).splice) } tree case _ => tree } } def embedFun[A, B](c: Context)(f: c.Expr[A => Term[B]]): c.Expr[A ~> B] = { import c.universe._ f.tree match { case Function(args, body) => reify { Abs(Var(c.literal(args.head.name.decoded).splice), c.Expr[Term[B]](embedVars(c)(body)).splice ) }} } trait Back { implicit def funLifting[A, B](f: A => Term[B]): A ~> B = macro embedFun[A, B] } object Front extends Back { implicit def litLifting(x: Double): Term[Double] = macro embedLit } } def add = Sum }И теперь я могу:
object main extends App { import Sublang._ import Sublang.embeddings.Front._ def test[A, B](f: A ~> B) = println(f) test { x: Double => add(x, 0.5) } // => Abs(Var(x),Sum(Var(x),Num(0.5))) }А через, например, RebindableSyntax, из этого всего получится только Num вложить.
@ В чем разница?
В библиотеках комбинаторов обычно ничего такого мудрёного нету, чтоб их целесообразно было ещё какими-то DSL, EDSL или подъязыками называть.
Если оно и так хорошо вписывается в обычные хаскельные построения, значит, это обычный хаскельный код.
Вот когда он будет не вписываться в систему типов и, например, в стратегию биндинга, и вообще выглядеть инородно (при попытке выразить без мета-уровневых средств), тогда будет смысл говорить о чём-то подобном.
no subject
Вообще-то, именно их и называют EDSL. Это синонимы.
Если мы повторяем синтаксис стороннего языка в языке носителе, то это называется EDSL. Так уж получилось, что применение функций и абстрагирование позволяет повторить (с точностью до синтаксических преобразований) синтаксис многих других языков.
Термин появился задолго до того, как вы стали изучать Scala. Я столкнулся с ним в 1999-ом, в контексте комбинаторов синтаксического разбора.
>Вот, смотрите:
Я не могу это читать. У меня голова по-другому работает. Я не для того решил в 1998 году уйти от объектов и наследований, чтобы возвращаться обратно.
Дайте мне алгебраическую структуру и я счастлив.
>А как они помогут пронаблюдать имя переменной лямбды и имена свободных термов?
Применением.
instance (B a, G b) => G (a -> b) where dadam f = do a <- inventArg b <- applyG f a dadam bПримерно так.Внутри функции f будут известны её параметры, как переменные.
См. также REPA и Accelerate.
no subject
Вот же:
На хаскеле это будет что-то такое:
{-# LANGUAGE GADTs #-} data Term :: * -> * where Num :: Double -> Term Double Sum :: Term Double -> Term Double -> Term Double ... type (a ~> b) = Term (a -> b)@ Применением.
Просто так по этому коду трудно понять, о чём речь. Где-нибудь можно посмотреть определение B, G, applyG?
Это не hoas хоть какой-нибудь? Речь же о том, чтобы иметь возможность делать произвольные биндеры, а с hoas получится, что если мы хотим какие-то другие, то нам надо сделать 2 подъязыка - первый - просто чтобы пронаблюдать переменные и оттранслировать лямбда-абстракции во второй. И ещё первый будет накладывать существенные ограничения на синтаксис подъязыка и на взаимодействие с хост-языком. Если получится, что любая лямбда-абстракция, которую мы хотим оттранслировать в конечный подъязык, на уровне хаскеля должна быть типа (SomeVarType -> SomeTermType), то это неприкольно, если нам хочется внутри её заиспользовать так, будто у неё её честный тип.
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
Нет, не соглашусь, синтаксис хаскеля намного лучше, с-образный синтаксис вообще для языков с фя-элементами не подходит (про полноценные фя я и не говорю).
no subject