[Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 27.04.11 16:09
Оценка: 2 (1)
Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.
Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.
def foo(x): if x == 0 then 0 else "bar" end


Я предлагаю статически типизированое решение, что то похожее на
let foo x = if x == 0 then 0 else "bar" end
foo :: int -> int | string

На что он делает два утверждения
а) действительно разобраться в том, что такое "алгебраический тип" и почему приведенный вами код никакого к ним отношения не имеет.
б) почитать о том, что такое система типов и почему приведенный вами код является классическим (см. того же Пирса) примером кода, который не пропустит любая система типов.

Насколько я понимаю, до сих пор эти высказывания в силе.
Интересует достоверность высказывания б). Может ли кто объяснить не ссылаясь на священые писания почему это так. Я умных книжек не читал поэтому совершено не вижу в чем тут может быть проблема, какая разница один тип или несколько, плюс мне видится это это вполне реализуемое как сахар поверх какого нибудь
type IntString = X of int | Y of string


Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: Temoto  
Дата: 27.04.11 16:47
Оценка: +1
D>Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.
D>Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.
D>
D>def foo(x): if x == 0 then 0 else "bar" end
D>


D>Я предлагаю статически типизированое решение, что то похожее на

D>
D>let foo x = if x == 0 then 0 else "bar" end
D>foo :: int -> int | string
D>

D>На что он делает два утверждения
D>а) действительно разобраться в том, что такое "алгебраический тип" и почему приведенный вами код никакого к ним отношения не имеет.
D>б) почитать о том, что такое система типов и почему приведенный вами код является классическим (см. того же Пирса) примером кода, который не пропустит любая система типов.

D>Насколько я понимаю, до сих пор эти высказывания в силе.

D>Интересует достоверность высказывания б). Может ли кто объяснить не ссылаясь на священые писания почему это так. Я умных книжек не читал поэтому совершено не вижу в чем тут может быть проблема, какая разница один тип или несколько, плюс мне видится это это вполне реализуемое как сахар поверх какого нибудь
D>
D>type IntString = X of int | Y of string
D>


Чёрт знает насчёт теоретически возможного, но в текущих языках с АТД (Haskell, Ocaml) такой фокус не прокатит, потому что вызывающая функция должна явно "распаковывать" строковое или численное значение из типа IntString с помощью матчинга на один из конструкторов. Кроме того, по крайней мере в хацкеле, внутри модуля конструкторы уникальны.

То есть type IntString объявить действительно несложно и объявить функцию, которая его возвращает, даже неявно — несложно. А вот как вы себе представляете использование такой функции?

D>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.


Это у кого куда мозг повёрнут. Любители динамики совершенно спокойно мыслят функциями, которые утром возвращают строку, а вечером boolean; любители статики от такого делят на ноль и начинают собирать аргументы против. Мой посыл заключается в том, что здравость (любой) идеи всегда будет оценена субъективно, то есть обсуждение скатится в срач — оно вам надо?

Чтобы не для срача, а конструктивно, нужно выбрать точку отсчёта (например, такая зависимость нам не нужна, а когда другие её используют мы будем делать так-то и так-то) и/или критерий оценки (например, сложность реализации компилятора, который подобное схавает).

Если для срача, то идея бредовая. Функции должны иметь постоянную сигнатуру. Навскидку не припомню, чтобы понадобилось обратное.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 27.04.11 16:57
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Чёрт знает насчёт теоретически возможного, но в текущих языках с АТД (Haskell, Ocaml) такой фокус не прокатит, потому что вызывающая функция должна явно "распаковывать" строковое или численное значение из типа IntString с помощью матчинга на один из конструкторов. Кроме того, по крайней мере в хацкеле, внутри модуля конструкторы уникальны.


T>То есть type IntString объявить действительно несложно и объявить функцию, которая его возвращает, даже неявно — несложно. А вот как вы себе представляете использование такой функции?


Матчинг будет не по конструктору а по типу

let x =
    match x with
    | :? Int as y -> print "is int"
    | :? String as y -> print "is string"


D>>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.


T>Это у кого куда мозг повёрнут. Любители динамики совершенно спокойно мыслят функциями, которые утром возвращают строку, а вечером boolean; любители статики от такого делят на ноль и начинают собирать аргументы против. Мой посыл заключается в том, что здравость (любой) идеи всегда будет оценена субъективно, то есть обсуждение скатится в срач — оно вам надо?

Кто же спорит, кто то любит биться головой об стену, кто то нет. За объективность всегда можно взять мнение большенства, конечно учитывая что большенство может при этом быть не правым.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: FR  
Дата: 27.04.11 17:08
Оценка: 6 (2)
Здравствуйте, dotneter, Вы писали:

D>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.


В OCaml есть вещь которая позволяет сделать нечто подобное, полиморфные варианты http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#toc36

open Printf

let foo x = 
  if x = 0 then `MyInt 0 else `MyStr "bar"
  
  
let print = function
  | `MyInt x -> printf "`MyInt = %d\n" x
  | `MyStr x -> printf "`MyStr = %s\n" x
  | `MyFloat x -> printf "`MyStr = %f\n" x
  
let _ = print (foo 0)
let _ = print (foo 1)


Их не нужно описывать перед использованием и они расширяемые, но как раз ослабляют статическую типизацию, и привносят
в язык динамику http://www.rsdn.ru/forum/decl/4032286.flat.aspx
Автор: Воронков Василий
Дата: 10.11.10
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 27.04.11 17:20
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.

D>Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.
Весьма сомнительно желание.

D>а) действительно разобраться в том, что такое "алгебраический тип" и почему приведенный вами код никакого к ним отношения не имеет.

D>б) почитать о том, что такое система типов и почему приведенный вами код является классическим (см. того же Пирса) примером кода, который не пропустит любая система типов.
Гонит по обоим пунктам.

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

Вполне себе вариант.
правда и сигнатуру функции тогда уж описывать так
foo :: int -> X int | Y string
let foo x = if x == 0 then X 0 else Y "bar" end


Ибо вот это:
let x =
    match x with
    | :? Int as y -> print "is int"
    | :? String as y -> print "is string"

Мне определенно не нравится.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: deniok Россия  
Дата: 27.04.11 17:23
Оценка: +1
Здравствуйте, dotneter, Вы писали:
...

Я не понял ни тезиса, ни антитезиса, но можно так
foo :: Int -> Either Int String
foo x = if x == 0 then Left 0 else Right "bar"

Использовать так
> either (+42) length $ foo 0
42
> either (+42) length $ foo 1
3
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: palm mute  
Дата: 27.04.11 17:30
Оценка: 2 (1)
Здравствуйте, dotneter, Вы писали:

D>Я предлагаю статически типизированое решение, что то похожее на

D>
D>let foo x = if x == 0 then 0 else "bar" end
D>foo :: int -> int | string
D>


Вроде бы в в Typed Scheme (входит в Racket, ранее известный как PLT Scheme) реализовано в точности это, называется union types.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 27.04.11 17:34
Оценка:
Здравствуйте, deniok, Вы писали:

D>Здравствуйте, dotneter, Вы писали:

D>...

D>Я не понял ни тезиса, ни антитезиса, но можно так

D>
D>foo :: Int -> Either Int String
D>foo x = if x == 0 then Left 0 else Right "bar"
D>

D>Использовать так
D>
>> either (+42) length $ foo 0
D>42
>> either (+42) length $ foo 1
D>3
D>

Это как раз и есть обобщеный IntString, вопрос можно ли убрать у
data Either a b = Left a | Right b
все имена оставив только a | b
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 27.04.11 17:34
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Вполне себе вариант.

WH>правда и сигнатуру функции тогда уж описывать так
WH>
WH>foo :: int -> X int | Y string
WH>let foo x = if x == 0 then X 0 else Y "bar" end
WH>


WH>Ибо вот это:

WH>
WH>let x =
WH>    match x with
WH>    | :? Int as y -> print "is int"
WH>    | :? String as y -> print "is string"
WH>

WH>Мне определенно не нравится.

Чем оно сильно хуже кортежа? У того несколько позиций, у этого одна с несколькими типами. Мне как раз видется
(int | string)
(int , string)
неким подобием замкнутого базиса.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: deniok Россия  
Дата: 27.04.11 17:43
Оценка:
Здравствуйте, dotneter, Вы писали:


D>Это как раз и есть обобщеный IntString, вопрос можно ли убрать у

D>data Either a b = Left a | Right b
D>все имена оставив только a | b

Ну, отдавая себе отчёт в том, что для дальнейшей унифицированной работы с получившимся хозяйством нужна (упорядоченная) пара функций (a->c)*(b->c), почему бы нет?
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: Temoto  
Дата: 27.04.11 21:58
Оценка: +1
T>>Чёрт знает насчёт теоретически возможного, но в текущих языках с АТД (Haskell, Ocaml) такой фокус не прокатит, потому что вызывающая функция должна явно "распаковывать" строковое или численное значение из типа IntString с помощью матчинга на один из конструкторов. Кроме того, по крайней мере в хацкеле, внутри модуля конструкторы уникальны.

T>>То есть type IntString объявить действительно несложно и объявить функцию, которая его возвращает, даже неявно — несложно. А вот как вы себе представляете использование такой функции?


D>Матчинг будет не по конструктору а по типу


D>
D>let x =
D>    match x with
D>    | :? Int as y -> print "is int"
D>    | :? String as y -> print "is string"
D>


Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 28.04.11 05:43
Оценка:
Здравствуйте, Temoto, Вы писали:


T>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.

Ну в этом суть статики, нужно переодически подсказывать компилятору что да как, что бы избежать ряда проблем.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: Tilir Россия http://tilir.livejournal.com
Дата: 28.04.11 06:37
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.

D>Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.
D>
D>def foo(x): if x == 0 then 0 else "bar" end
D>


И что? Даже в динамических языках функции возвращают значения одного и того же типа -- вариантного да, но не изменяемого значениями входных аргументов. foo *не возвращает* разные типы -- она возвращает один тип, просто этот тип допускает строковые и числовые значения.

Вопрос в том -- надо ли нам ограничивать типы насколько возможно (статический случай) или отпустить их насколько возможно (динамические языки). И тут я вижу два аргумента.

Один -- низкоуровневый, для С и подобных.

Сигнатура функции и типы её входных данных -- важная помощь компилятору в оптимизации. Сравните:

int f(int x);
void *f(void *x);


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

Второй -- высокоуровневый.

В таких языках как Haskell эта помощь становится не только помощью компилятору в производительности, но и помощью программисту в формировании абстракции. Рассмотрим пример вашего оппонента -- имея такую функцию ему придётся городить в коде рантаймовую проверку типа, который реально вернула foo на вызове foo(i), и есть шанс забыть, совершить ошибку, использовать не то значение и т.п. в Haskell же достаточно написать Either и сматчить Left / Right, как было показано выше по ветке -- и даже это уже во-первых произойдёт на компиляции во-вторых убережёт от кучи ошибок, в третьих сократит код.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: artelk  
Дата: 28.04.11 07:48
Оценка:
Здравствуйте, dotneter, Вы писали:

Тогда уж и такой полиморфизм изобразить можно было бы :
let foo x = if x == 0 then 0 else "hi" end
foo :: int -> int | string

let bar i = i + 1
let bar s = s + "\n"

let x1 = foo 0
x1 :: int | string

let x2 = foo 1
x2 :: int | string

//Магия:
let z1 = bar x1
z1 :: int | string

let z2 = bar x2
z2 :: int | string
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: deniok Россия  
Дата: 28.04.11 08:21
Оценка:
Здравствуйте, artelk, Вы писали:

A>Здравствуйте, dotneter, Вы писали:


A>Тогда уж и такой полиморфизм изобразить можно было бы :

A>
A>let bar i = i + 1
A>let bar s = s + "\n"
A>//Магия:
A>let z1 = bar x1
A>z1 :: int | string
A>let z2 = bar x2
A>z2 :: int | string
A>


Зачем себя ограничивать ad hoc полиморфизмом, когда можно определить параметрически
mapSum :: (a -> c) -> (b -> d) -> a | b -> c | d

и обслуживать себе любую сумму:
z :: int | string -> int | string
z = mapSum (\i -> i + 1) (\s -> s + "\n")
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 28.04.11 08:30
Оценка:
Здравствуйте, deniok, Вы писали:

D>Зачем себя ограничивать ad hoc полиморфизмом, когда можно определить параметрически

D>
D>mapSum :: (a -> c) -> (b -> d) -> a | b -> c | d
D>

Плохая идея.
Что будешь делать если понадобиться маписать объедение 3х типов? Еще одну функцию писать?
А если три типа в два? А два в три?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 28.04.11 08:33
Оценка:
Здравствуйте, artelk, Вы писали:

Вроде все тоже самое, можно было остановится на

A>let bar i = i + 1

A>let bar s = s + "\n"

bar :: int | string -> int | string

Тут же как раз работает матчинг по типу.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 28.04.11 08:43
Оценка:
Здравствуйте, WolfHound, Вы писали:
Для кортежей тоже приходятся писать новые функции
fst (a,_)
fst (a,_,_)
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: deniok Россия  
Дата: 28.04.11 08:44
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, deniok, Вы писали:


D>>Зачем себя ограничивать ad hoc полиморфизмом, когда можно определить параметрически

D>>
D>>mapSum :: (a -> c) -> (b -> d) -> a | b -> c | d
D>>

WH>Плохая идея.
WH>Что будешь делать если понадобиться маписать объедение 3х типов? Еще одну функцию писать?

Зачем, уже написана:
(f `mapSum` g) `mapSum` h :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> (a1 | a2) | a3 -> (b1 | b2) | b3

Если ещё задать разумную ассоциативность, то
f `mapSum` g `mapSum` h :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> a1 | a2 | a3 -> b1 | b2 | b3


WH>А если три типа в два? А два в три?

А это уже другие задачи
Re[5]: Техническая поправка
От: deniok Россия  
Дата: 28.04.11 08:49
Оценка:
Здравствуйте, deniok, Вы писали:

Лямбды забыл спереди
\f g h -> f `mapSum` g `mapSum` h :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> a1 | a2 | a3 -> b1 | b2 | b3

но идея ясна.
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: artelk  
Дата: 28.04.11 09:20
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, artelk, Вы писали:


D>Вроде все тоже самое, можно было остановится на


A>>let bar i = i + 1

A>>let bar s = s + "\n"

D>bar :: int | string -> int | string


D>Тут же как раз работает матчинг по типу.


Ага. Но разные bar могут лежать в разных "сборках".
Именно такой тип конструируется для bar, хотя, например, "bar 1" все еще должен вернуть int, а не анонимный int|string.
Если оба типа принадлежат одному классу типов, то тоже можно было бы создавать такой bar по месту:
class Plusable a where
  (+) :: a -> a -> b

instance Plusable Int where
  ...
instance Plusable String where
  ...

bar :: (Plusable a) => a -> a -> a
let bar (Plusable x) = x + x + x

let z1 = bar x1
z1 :: int | string


ЗЫ (С) Слабо-сильно типизированный язык программирования
Re: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 28.04.11 18:12
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Давече господину Воронкову Василию был задан вопрос, зачем нужен динамик.

D>Что бы возвращать разные типы из функции в записимости от входящих параметров, отвечает он.

Исходный пример я пропустил. Он мне не нравится. Предлагаю более интересный вариант (из практики):
public static function exceptionProtect(f : Function, exnHandler : Function) : Function {
  return function(...args) : * {
    try {
      return f.applly(null, args);
    } catch (e : *) {
      exnHandler(e);
      throw e;
    }
  }
}

Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

D>Я предлагаю статически типизированое решение, что то похожее на

D>
D>let foo x = if x == 0 then 0 else "bar" end
D>foo :: int -> int | string
D>

А что именно даст статическая типизация? Она будет только для проверки "корректности" кода или еще как-то использоваться в процессе компиляции?

D>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.

Идея интересная. Применительно к динамике я бы еще хотел возможность написать код, вычисляющий тип результата (и выполняющий некоторые проверки) для функции и выполняющийся по каждому метсу вызова. Например, для приведенного мной примера я могу сказать, что именно получится в результате. Более того, все получающиеся преобразования типов в своем коде (на данный момент) я могу описать зная типы исходных аргументов. Если позволить читать внешние метаданные, я могу проверить вообще все типы в программе (часть динамики управляется внешним конфигом в рантайме).

Вообще, сама идея здравая. Но для этого рантайм должен позволять делать нетривиальные вещи. Например, создавать новые типы (классы), вызывать в обобщенной форме функции и т.п. В этом случае "обобщенные" функции могут как-то преобразовывать тип своих аргументов. Что-то вроде недомакросов но при этом в рантайме. Тогда тип результата будет нетривиальным образом зависеть от типов (возможно — и значений) входных параметров. Ну и для проверки корректности, естественно, хотелось бы вычислять типы результатов вызова таких функций (или еще какую-либо информацию).
Re[2]: Анонимные алгебраические типы. Более сложный случай.
От: dotneter  
Дата: 28.04.11 18:41
Оценка:
Здравствуйте, maxkar, Вы писали:


M>Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

Вам тут нужен макрос, а не статическая типизация.


D>>Так же можно обсудить, общую здравость идеи зависимости сигнатуры функции от входящих параметров.

M>Идея интересная. Применительно к динамике я бы еще хотел возможность написать код, вычисляющий тип результата (и выполняющий некоторые проверки) для функции и выполняющийся по каждому метсу вызова. Например, для приведенного мной примера я могу сказать, что именно получится в результате. Более того, все получающиеся преобразования типов в своем коде (на данный момент) я могу описать зная типы исходных аргументов. Если позволить читать внешние метаданные, я могу проверить вообще все типы в программе (часть динамики управляется внешним конфигом в рантайме).

M>Вообще, сама идея здравая. Но для этого рантайм должен позволять делать нетривиальные вещи. Например, создавать новые типы (классы), вызывать в обобщенной форме функции и т.п. В этом случае "обобщенные" функции могут как-то преобразовывать тип своих аргументов. Что-то вроде недомакросов но при этом в рантайме. Тогда тип результата будет нетривиальным образом зависеть от типов (возможно — и значений) входных параметров. Ну и для проверки корректности, естественно, хотелось бы вычислять типы результатов вызова таких функций (или еще какую-либо информацию).

Этот поток сознания я не осилил, но похоже вы опять про макросы.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dimgel Россия https://github.com/dimgel
Дата: 28.04.11 23:04
Оценка:
Здравствуйте, Temoto, Вы писали:

D>>
D>>let x =
D>>    match x with
D>>    | :? Int as y -> print "is int"
D>>    | :? String as y -> print "is string"
D>>


T>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:

if (is_int($x)) {
   exit($x);
} else {
   // do something with string $x
}
Re[3]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 29.04.11 08:18
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Вам тут нужен макрос, а не статическая типизация.


Зачем это мне здесь нужен макрос? Почему вы решили, что я хочу во время компиляции генерировать какой-то код, а не в рантайме в динамике оборачивать функцию? Тем более что в коде эта функция используется в том контексте, в котором макросы не помогут. Ей на вход кормится страшная функция, собираемая по внешнему конфигу. Исходная функция — interop между всеми модулями приложения и заодно repository, из которого модули получают необходимые им сервисы. Ну а обертка — фактически, одна простая и короткая возможность вывести пользователю "правильные" сообщения об ошибке если что-то пошло не так. Ну и что можно макросом здесь сделать? А вот написать правила преобразования типов этой функцией я вполне мог бы.
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: dotneter  
Дата: 29.04.11 08:39
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Здравствуйте, dotneter, Вы писали:


D>>Вам тут нужен макрос, а не статическая типизация.


M>Зачем это мне здесь нужен макрос? Почему вы решили, что я хочу во время компиляции генерировать какой-то код, а не в рантайме в динамике оборачивать функцию?

Я решил что вам нужен статически типизированый врапер для функции, это задача кодогенерации, значит нужен макрос
Я не знаю что у вас там за конструктор страшны функции, но если у вас есть функция
void Foo(){DoSomething()}


То с помощью кодогеренации можно сделать врапер, хоть так
void Foo() { try DoSomething catch }


хоть так
Action GetWraper(Action x){
  return () => {try DoSomething catch}
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 11:24
Оценка:
Здравствуйте, dotneter, Вы писали:

Ты все перевернул с ног на голову.

Есть два варианта:
+ Функция, тип которой зависит от [типа] параметров
+ Функция, тип которой зависит от значений параметров

Первый вариант в статике возможен:

printf "%d+%d=%d" 2 2 (2+2)

Второй — нет:

let myPrint fmt = printf fmt ...?

То, что ты приводишь:

def foo(x): if x == 0 then 0 else "bar" end

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

data Either a b = Left a | Right b
foo x | x == 0 = Left 0
| otherwise = Right "bar"

Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

let foo x | x == 0 = 0
| else = "bar"

Имеет тип, зависящий от *значения* х. Поэтому код вида:

foo 0 * foo 0

верный и отработает. Но код:

foo 0 * foo 1

неверный и свалится в рантайме.

Системы типов консервативны, они не пытаются доказать правильность программы, они доказывают ее возможную неправильность. Код вида foo x * foo y возможно неправильный (но частный случай foo 0 * foo 0 — правильный). Исходя из того, что выражение foo x * foo y в принципе может быть неправильным, система типов этот код не пропустит.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 11:26
Оценка:
Здравствуйте, WolfHound, Вы писали:

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

WH>Вполне себе вариант.
WH>правда и сигнатуру функции тогда уж описывать так
WH>
WH>foo :: int -> X int | Y string
WH>let foo x = if x == 0 then X 0 else Y "bar" end
WH>


Тип этой функции не зависит от значений параметров. Тип *всегда* int|string.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 11:45
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>data Either a b = Left a | Right b

ВВ>foo x | x == 0 = Left 0
ВВ> | otherwise = Right "bar"
Да, разве что без надобности вводить тип.

ВВ>Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

Да, но решает туже задачу.

ВВ>let foo x | x == 0 = 0

ВВ> | else = "bar"

ВВ>Имеет тип, зависящий от *значения* х. Поэтому код вида:


ВВ>foo 0 * foo 0


ВВ>верный и отработает. Но код:


ВВ>foo 0 * foo 1


ВВ>неверный и свалится в рантайме.

Суть как раз в том что в статике ничего не свалится, компилятор не даст.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 13:43
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>data Either a b = Left a | Right b

ВВ>>foo x | x == 0 = Left 0
ВВ>> | otherwise = Right "bar"
D>Да, разве что без надобности вводить тип.

Без надобности, да. Вот только если тип не вводить, то все автоматически объявляемые конструкторы будут принадлежать одному типу. И тип функции

foo x = if x == 0 then 0 else "bar"


будет точно такой же, как и у

bar x = if x == 0 then 42.42 else 'b'


И спрашивается, чем это вообще отличается от динамики.

Собственно, есть мнение, что динамика — это статика, в которой есть лишь один-единственный тип.

ВВ>>Тип функции foo при этом — Either. Этот тип вообще никак не зависит от параметров. Аналогичная ф-ция foo в динамике:

D>Да, но решает туже задачу.

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

ВВ>>неверный и свалится в рантайме.

D>Суть как раз в том что в статике ничего не свалится, компилятор не даст.

Да, потому что в статике компилятор просто не скомпилирует эквивалетный код.
Re[5]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 13:45
Оценка:
Здравствуйте, dimgel, Вы писали:

T>>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


D>В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:


Нет, не то же самое. В динамике будет утиная типизация.
Re[2]: Анонимные алгебраические типы. Более сложный случай.
От: FR  
Дата: 29.04.11 13:47
Оценка: 14 (2)
Здравствуйте, maxkar, Вы писали:

M>Исходный пример я пропустил. Он мне не нравится. Предлагаю более интересный вариант (из практики):

M>
M>public static function exceptionProtect(f : Function, exnHandler : Function) : Function {
M>  return function(...args) : * {
M>    try {
M>      return f.applly(null, args);
M>    } catch (e : *) {
M>      exnHandler(e);
M>      throw e;
M>    }
M>  }
M>}
M>

M>Эта функция принимает функцию (с произвольным числом и типом аргументов, более точной типизации функций в языке нет) и возвращает функцию, которая добавляет дополнительный уровень обработки исключений. Для всех возникших в f исключений вызывается exnHandler и исключение пробрасывается дальше. Работает для всех функций — с любым числом и типами аргументов, корректно работает с опциональными параметрами. Вопрос: а как оно будет выглядеть в вашем статически типизированном решении?

Если в языке достаточно развитое метапрограммирование будет выглядеть вполне прилично, вот например вариант на шаблонах D:

import std.traits;
import std.conv;
import std.stdio;


template ExceptionProtect(alias Fun, alias ExnHandler)
{
    ReturnType!Fun ExceptionProtect(ParameterTypeTuple!Fun args)
    {
    ReturnType!Fun Result;
    
    try{
        Result = Fun(args);
        }    
    catch(Exception e){
        ExnHandler(e);
        throw e;
        }
    
    return Result;
    }    
}


string TestInc(int i)
{
    if(i > 0)
        return text("Ok result = ", i + 1);
    else
        throw new Exception("TestInc() failed");
    
    return "Fail";
}


void TestExnHandler(Exception e)
{
    writeln("TestExnHandler run");
}

void main()
{
    writeln(ExceptionProtect!(TestInc, TestExnHandler)(123));
    writeln(ExceptionProtect!(TestInc, TestExnHandler)(-1));
}
Re[6]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, dimgel, Вы писали:


T>>>Если матчинг обязательный явный, то оно есть уже сегодня, если конструкторы будут названы так же: Int и String. Но я не думаю, что анонимность конструкторов тут самая большая беда. Чтобы воспользоваться значением, его всё-таки придётся из алгебраического типа распаковать — вот что самое неудобное. В динамике "оно само", без лишних switch/match.


D>>В динамике практически то же самое, если со возвращённым значением предполагается делать что-либо посложнее, чем тупо вывести его в строку:


ВВ>Нет, не то же самое. В динамике будет утиная типизация.

Чем вас не устраивает структурная?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[4]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>foo x = if x == 0 then 0 else "bar"
ВВ>


ВВ>будет точно такой же, как и у


ВВ>
ВВ>bar x = if x == 0 then 42.42 else 'b'
ВВ>

Почему такой же? int|string double|string

ВВ>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

Можете привести пример еще раз, но что бы он не пытался взорвать мозг, и максимально просто отражал то что вы хотите.

ВВ>>>неверный и свалится в рантайме.

D>>Суть как раз в том что в статике ничего не свалится, компилятор не даст.

ВВ>Да, потому что в статике компилятор просто не скомпилирует эквивалетный код.

Не скомпилирует он только то что нельзя с полной увереностью сказать сработает при всех возможных сочетаниях типов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[7]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 14:28
Оценка: +1
Здравствуйте, dotneter, Вы писали:

ВВ>>Нет, не то же самое. В динамике будет утиная типизация.

D>Чем вас не устраивает структурная?

Структурная работает только если типы выводятся.
Re[5]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 14:31
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>
ВВ>>bar x = if x == 0 then 42.42 else 'b'
ВВ>>

D>Почему такой же? int|string double|string

Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?
И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?

ВВ>>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

D>Можете привести пример еще раз, но что бы он не пытался взорвать мозг, и максимально просто отражал то что вы хотите.

Скажи, что тебе конкретно взрывает мозг, и я попробую упростить пример именно в этом месте.
Re[8]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, dotneter, Вы писали:


ВВ>>>Нет, не то же самое. В динамике будет утиная типизация.

D>>Чем вас не устраивает структурная?

ВВ>Структурная работает только если типы выводятся.

И? Ну и пусть выводятся.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[6]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 14:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, dotneter, Вы писали:


ВВ>>>
ВВ>>>bar x = if x == 0 then 42.42 else 'b'
ВВ>>>

D>>Почему такой же? int|string double|string

ВВ>Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?

Можете :: (Num a) => a|string ->
ВВ>И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?
Вы же в той ветке отвечали
http://rsdn.ru/forum/philosophy/4251489.1.aspx
Автор: dotneter
Дата: 27.04.11

или так
bar x :: int ->
bar x :: string ->

ВВ>>>Этот код ты сам придумал, и я знаю, какую задачу он решает. Я приводил другие примеры, и на статике они не выражаются.

D>>Можете привести пример еще раз, но что бы он не пытался взорвать мозг, и максимально просто отражал то что вы хотите.

ВВ>Скажи, что тебе конкретно взрывает мозг, и я попробую упростить пример именно в этом месте.

let fun (x::xs) = fun' x xs
where fun' a [] = \y -> y + a
fun' a (x::xs) = \y -> fun' (y + a + x) xs
Обязательно нужно работать со списками, и в обоих случаях возвращать функции, проще ничего не придумать?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 29.04.11 14:56
Оценка:
Здравствуйте, FR, Вы писали:

FR>Если в языке достаточно развитое метапрограммирование будет выглядеть вполне прилично, вот например вариант на шаблонах D:


Да, неплохо. Только вот мне не нравится, что это шаблон. Я хочу именно функцию. Чтобы ее можно было куда-нибудь еще передавать, например. Я не против писать то, что в шаблоне написано, это позволит проверить типы там, где они известны на этапе компиляции. А там, где функция используется на динамике, пусть работает в "моем" варианте. Более того, пусть "статические" вызовы компилятор инлайнит, но динамика все равно остается. Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде
const cls : Class = findClass(config.confClass);
const instance : Object = new Class();
const func = instance[config.confMethod];
return exceptoinProtect(func, protector);


Более того, на основе этой же функции я могу, например, защищать "интерфейсы":
function protectInterface(iface : Object, protector : Function) : Object {
  const res : Object = {};
  for (var item : String in iface) {
    var val : Object = iface[item];
    var valf : Function = val as Function;
    res[item] = valf != null ? exceptionProtect(valf, protector) : val;
  }  
  return res;
}

Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены. Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия. На шаблонах оно будет работать только до тех пор, пока известна информация о типах преобразуемых объектов.

Вообще, вся эта магия нужна, когда присутствуют сразу оба типа варианта, описаных Василием. Есть функция, тип результата которой зависит от значения. Такая функция возникает, когда есть какая-либо внешная конфигурация "верхнего" уровня, не выраженная в коде. И при этом есть функции, тип которых зависит от типа аргументов, вроде приведенных выше. В статическом случае их можно реализовать шаблонами/макросами и т.п. Но вот применить их к результату функций первого типа не получится без динамики .
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: FR  
Дата: 29.04.11 15:24
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Да, неплохо. Только вот мне не нравится, что это шаблон. Я хочу именно функцию. Чтобы ее можно было куда-нибудь еще передавать, например.


Этот шаблон порождает полноценную функцию полностью совпадающую по типу с ее функцией аргументом, с ней можно делать все что можно делать с любой другой функцией. Тут чуть разъясню, шаблоны D в отличии от шаблонов C++ могут порождать любые типы, а не только структуры/классы или функции.
Вот такой код:

writeln(typeid(typeof(TestInc)));
writeln(typeid(typeof(ExceptionProtect!(TestInc, TestExnHandler))));


выведет:

immutable(char)[]()
immutable(char)[]()


то есть типы совершенно одинаковы, от шаблона ничего ни осталось.

M>Я не против писать то, что в шаблоне написано, это позволит проверить типы там, где они известны на этапе компиляции. А там, где функция используется на динамике, пусть работает в "моем" варианте. Более того, пусть "статические" вызовы компилятор инлайнит, но динамика все равно остается. Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде


В динамике конечно шаблоны бессильны.

.....

M>Более того, на основе этой же функции я могу, например, защищать "интерфейсы":


.....

M>Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены.


А это на шаблонах вполне реально.

M>Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия. На шаблонах оно будет работать только до тех пор, пока известна информация о типах преобразуемых объектов.


Конечно, но тут часто хватает обертки на базовый интерфейс.

M>Вообще, вся эта магия нужна, когда присутствуют сразу оба типа варианта, описаных Василием. Есть функция, тип результата которой зависит от значения. Такая функция возникает, когда есть какая-либо внешная конфигурация "верхнего" уровня, не выраженная в коде. И при этом есть функции, тип которых зависит от типа аргументов, вроде приведенных выше. В статическом случае их можно реализовать шаблонами/макросами и т.п. Но вот применить их к результату функций первого типа не получится без динамики .


Это да.
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: WolfHound  
Дата: 29.04.11 16:09
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде

Ну строится.
Ну по конфигу.
Дальше то что?
Почему у функции тип не известен?

M>Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены. Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия.

Давай конкретный пример.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 29.04.11 16:28
Оценка:
Здравствуйте, dotneter, Вы писали:

D>let fun (x::xs) = fun' x xs

D> where fun' a [] = \y -> y + a
D> fun' a (x::xs) = \y -> fun' (y + a + x) xs
D>Обязательно нужно работать со списками, и в обоих случаях возвращать функции, проще ничего не придумать?
Тут бред какой-то написан.
Что он делает то?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 16:31
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>>>
ВВ>>>>bar x = if x == 0 then 42.42 else 'b'
ВВ>>>>

D>>>Почему такой же? int|string double|string

ВВ>>Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?

D>Можете :: (Num a) => a|string ->

А как же int|char? int|double|string? int|int|int|string|bool?
Но даже неважно.

(Num a) — это вообще тайп-класс констрейнт. Вы именно это имели ввиду? Тогда я не понимаю — Num это словарь через который передаются функции. Фактически подобная запись позволяет нам записать базовую арифметику типа сложения и вычитания, не зная даже, работает ли мы с целыми или вещественными числами. Это, по-моему, совсем не то, о чем речь.

Если вы имели в виду генерик-функцию, то мне тоже не очень понятно, что там должно быть внутри. Генерик должен быть как-то специализирован. Но в данном случае тайп-параметром генерика является то, что нам известно только в рантайме. Т.е. то, что тип (int|string) мы конечно выведем при компиляции, но как вызвать функцию для проверки? Как мы укажем, что должно быть вместо этого самого "а"? Ведь это станет известно только в рантайме.

Задача вообще написать аналог:

foo x = if x == 0 then Left 0 else Right "bar"

case x of
     Left _ -> ...
     Right _ -> ...


ВВ>>И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?

D>Вы же в той ветке отвечали
D>http://rsdn.ru/forum/philosophy/4251489.1.aspx
Автор: dotneter
Дата: 27.04.11

D>или так
D>bar x :: int ->
D>bar x :: string ->

"x :: int" — это сигнатура. Причем в ней указан int, а не int|string. Если имеется в виду что-то типа "x is int", то мне тоже не очень понятно. Т.е. данная проверка вернет true, если x это int и если x это int|string.

Причем даже это неважно.

int|string — это у нас такой тип. Он известен в компайл-тайм. Но в рантайм у него может быть одно значение — либо int, либо string. Задача — проверить, что там внутри на самом деле — int или string. Причем учитывая, что количество комбинаций x|y|z стремится к бесконечности сделать это как-нибудь так, чтобы не пришлось писать проверки на каждую конкретную комбинацию.

ВВ>>Скажи, что тебе конкретно взрывает мозг, и я попробую упростить пример именно в этом месте.

D>let fun (x::xs) = fun' x xs
D> where fun' a [] = \y -> y + a
D> fun' a (x::xs) = \y -> fun' (y + a + x) xs
D>Обязательно нужно работать со списками, и в обоих случаях возвращать функции, проще ничего не придумать?

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

Вам нужен пример с утка.КряКря?
Re[8]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 16:40
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Тут бред какой-то написан.

WH>Что он делает то?

let fun (x::xs) = fun' x xs 
                  where fun' a [] = \y -> y + a 
                        fun' a (x::xs) = \y -> fun' (y + a + x) xs

fun [1..3] 1 2 3 //saturation
fun [1..5] 1 2 3 4 5//saturation
Re[9]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 16:42
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>Структурная работает только если типы выводятся.

D>И? Ну и пусть выводятся.

А если не выводятся?
У структурных типов тоже много самых разных проблем. Опять же, какой самый распространенный структурный тип? Функциональный.

Запишешь мне какой будет тип у такой функции?

let out x = write x $ out


Аналог на ДжаваСкрипте:

function out (x) {
   write(x);
   return out;
}


Когда закончишь — позови.
Re[4]: Анонимные алгебраические типы. Более сложный случай.
От: WolfHound  
Дата: 29.04.11 16:47
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Ну а обертка — фактически, одна простая и короткая возможность вывести пользователю "правильные" сообщения об ошибке если что-то пошло не так.

Что-то мне подсказывает что тут происходит смешение логики с представлением.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 29.04.11 16:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>let fun (x::xs) = fun' x xs 
ВВ>                  where fun' a [] = \y -> y + a 
ВВ>                        fun' a (x::xs) = \y -> fun' (y + a + x) xs

ВВ>fun [1..3] 1 2 3 //saturation
ВВ>fun [1..5] 1 2 3 4 5//saturation
ВВ>

Что это?
Код ради кода?
Какая задача то решается?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 29.04.11 16:56
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Запишешь мне какой будет тип у такой функции?

ВВ>
ВВ>let out x = write x $ out
ВВ>

Тут нужна поддержка рекурсивных типов.
type MyType = [T] T -> MyType;
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 17:14
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>А как же int|char? int|double|string? int|int|int|string|bool?

ВВ>Но даже неважно.

ВВ>(Num a) — это вообще тайп-класс констрейнт. Вы именно это имели ввиду? Тогда я не понимаю — Num это словарь через который передаются функции. Фактически подобная запись позволяет нам записать базовую арифметику типа сложения и вычитания, не зная даже, работает ли мы с целыми или вещественными числами. Это, по-моему, совсем не то, о чем речь.

Вы говорите "Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?
"
Я говорю можете, для этого нужно использовать какой то их общий интерфейс, например Num



ВВ>Если вы имели в виду генерик-функцию, то мне тоже не очень понятно, что там должно быть внутри. Генерик должен быть как-то специализирован. Но в данном случае тайп-параметром генерика является то, что нам известно только в рантайме. Т.е. то, что тип (int|string) мы конечно выведем при компиляции, но как вызвать функцию для проверки? Как мы укажем, что должно быть вместо этого самого "а"? Ведь это станет известно только в рантайме.


ВВ>Задача вообще написать аналог:


ВВ>
ВВ>foo x = if x == 0 then Left 0 else Right "bar"

ВВ>case x of
ВВ>     Left _ -> ...
ВВ>     Right _ -> ...
ВВ>

По ссылке же и написан аналог
let bar x =
    match x with
    | :? Int as y -> print "is int"
    | :? String as y -> print "is string"

bar :: int|string -> void

ВВ>>>И кстати, как вообще анализировать тип? Как проверить, что функция вернула строку или число?

D>>Вы же в той ветке отвечали
D>>http://rsdn.ru/forum/philosophy/4251489.1.aspx
Автор: dotneter
Дата: 27.04.11

D>>или так
D>>bar x :: int ->
D>>bar x :: string ->

ВВ>"x :: int" — это сигнатура. Причем в ней указан int, а не int|string. Если имеется в виду что-то типа "x is int", то мне тоже не очень понятно. Т.е. данная проверка вернет true, если x это int и если x это int|string.

Да написан в одном случаи int в другом string в месте они образуют тип int|string
Это же тоже самое что
bar Right x =
bar Left x =

a|b Является полным аналогом Right a| Left b
При этом матчинг идет не по конструкторам, а по типам.

ВВ>int|string — это у нас такой тип. Он известен в компайл-тайм. Но в рантайм у него может быть одно значение — либо int, либо string. Задача — проверить, что там внутри на самом деле — int или string.

Вроде вверху это задача полность решена.
ВВ>Причем учитывая, что количество комбинаций x|y|z стремится к бесконечности сделать это как-нибудь так, чтобы не пришлось писать проверки на каждую конкретную комбинацию.
Это уже другая проблема. Для одной переменой достаточно написать три метода для каждого типа, для двух по три уже 9ть, если какие то вас явно не интересуют, можно использовать обобщения, и выкидывать лишнее.

ВВ>Вам нужен пример с утка.КряКря?

Да, имено это и нужно.Минимальный пример что бы не пришлось отвлекатся на то что можно опустить.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 17:26
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Когда закончишь — позови.

Наверное как то так.
Type X = object -> X
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 18:40
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Запишешь мне какой будет тип у такой функции?

ВВ>>
ВВ>>let out x = write x $ out
ВВ>>

WH>Тут нужна поддержка рекурсивных типов.
WH>type MyType = [T] T -> MyType;

Или просто *не* структурный тип. Например, на делегатах это спокойно выражается.
А вот в OCaml я смог это записать только через полиморфный вариант. Причем здесь-то тип на самом деле известен статически.
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 18:41
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

ВВ>>
ВВ>>let fun (x::xs) = fun' x xs 
ВВ>>                  where fun' a [] = \y -> y + a 
ВВ>>                        fun' a (x::xs) = \y -> fun' (y + a + x) xs

ВВ>>fun [1..3] 1 2 3 //saturation
ВВ>>fun [1..5] 1 2 3 4 5//saturation
ВВ>>

WH>Что это?
WH>Код ради кода?
WH>Какая задача то решается?

Конкретно это — код ради кода. Просто показать пример в... эээ... упрощенном виде.
Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 29.04.11 18:58
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Конкретно это — код ради кода. Просто показать пример в... эээ... упрощенном виде.

ВВ>Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.
Не смотря на то что строка формата задается в рантайме число аргументов и их типы известны статически.
Значит можно сделать статически типизированный аналог.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 29.04.11 18:58
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А вот в OCaml я смог это записать только через полиморфный вариант. Причем здесь-то тип на самом деле известен статически.

А вот так что не работает?
http://www.brool.com/index.php/recursive-types-in-ocaml
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 20:42
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

ВВ>>А вот в OCaml я смог это записать только через полиморфный вариант. Причем здесь-то тип на самом деле известен статически.

WH>А вот так что не работает?
WH>http://www.brool.com/index.php/recursive-types-in-ocaml

Ну через заглушку работает, но чем это от варианта отличается
А rectypes вообще достаточно стремная штука. К сожалению, она не просто включает рекурсивные типы, а еще и дает по голове тайп-чекеру так, что он начинает пропускать ошибочный код.
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 20:45
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Конкретно это — код ради кода. Просто показать пример в... эээ... упрощенном виде.

ВВ>>Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.
WH>Не смотря на то что строка формата задается в рантайме число аргументов и их типы известны статически.
WH>Значит можно сделать статически типизированный аналог.

Честно говоря, не вижу причин, по которым количество и типы аргументов обязательно должны быть всегда известны статически. Но даже это и неважно. Если ты строку формата не можешь явно скормить компилятору в виде константы, то он просто не сможет типизировать функцию. Другого пути нет.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 20:45
Оценка:
Здравствуйте, dotneter, Вы писали:

ВВ>>Когда закончишь — позови.

D>Наверное как то так.
D>Type X = object -> X

Что такое object? "Любой тип"?
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 20:58
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, dotneter, Вы писали:


ВВ>>>Когда закончишь — позови.

D>>Наверное как то так.
D>>Type X = object -> X

ВВ>Что такое object? "Любой тип"?

да
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[9]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 21:07
Оценка: +1
Здравствуйте, dotneter, Вы писали:

ВВ>>(Num a) — это вообще тайп-класс констрейнт. Вы именно это имели ввиду? Тогда я не понимаю — Num это словарь через который передаются функции. Фактически подобная запись позволяет нам записать базовую арифметику типа сложения и вычитания, не зная даже, работает ли мы с целыми или вещественными числами. Это, по-моему, совсем не то, о чем речь.

D>Вы говорите "Т.е. я не смогу написать одну полиморфную функцию, которая будет анализировать результат возвращаемый под видом int|string или double|string?
D>"
D>Я говорю можете, для этого нужно использовать какой то их общий интерфейс, например Num

Я себе такой интерфейс не представляю. И не уверен, что ты представляешь тоже. То, что ты описываешь под видом int|string и проч. больше всего похоже на кортежи. И покамест никакого интерфейса не придумали, чтобы можно было абстрагировать кортежи разной длины с разными элементами на основе типа какого-то одного из элементов.

Предположим, даже такой интерфейс есть. Что он тебе даст? Какие-то статические гарантии? Вряд ли. Как будет работать код для int|string у которого в рантайме задан string и для int|string, у которого в рантайме задан int?

D>По ссылке же и написан аналог

D>
D>let bar x =
D>    match x with
D>    | :? Int as y -> print "is int"
D>    | :? String as y -> print "is string"
D>

D>bar :: int|string -> void

Я думаю все можно гораздо проще. Зачем вообще эти int|string?

object foo(int x) {
  if (x == 0) return 0 else return "bar";
}

if (foo(0) is int) ...


Осталось только понять, чем твой вариант от этого отличается и какое это имеет отношение к статике.

ВВ>>"x :: int" — это сигнатура. Причем в ней указан int, а не int|string. Если имеется в виду что-то типа "x is int", то мне тоже не очень понятно. Т.е. данная проверка вернет true, если x это int и если x это int|string.

D>Да написан в одном случаи int в другом string в месте они образуют тип int|string
D>Это же тоже самое что
D>
D>bar Right x =
D>bar Left x =
D>


Честно, мне стоит определенных усилий догадываться, о чем ты пишешь. Где здесь голова функции, например? Может, лучше на Си-подобный синтаксис перейдешь?
И кстати это не тоже самое.
Науке пока известны две вещи:
+ Алгебраические типы, которые на языке ООП есть попросту закрытая одноуровневая иерархия наследования, не больше и не меньше.
+ Полиморфные варианты, все конструкторы которых к единой хербрандовой вселенной
В одном случае имеем жесткую статику, в другом — без пяти минут динамику. У тебя, как ты утверждаешь, ни первое ни второе.

D>a|b Является полным аналогом Right a| Left b

D>При этом матчинг идет не по конструкторам, а по типам.

Конструктор — это 1 12.3 'c'
Тип — это int real char
Не будем касаться того, что в православных языках ПМ вообще делается только по конструкторам, это бог с ним. Тут хотелось бы понять, каким образом ты хочешь делать матчинг по типам, указывая в качестве типа то, чем заматченный объект точно не является. Объект имеет тип int|string, а ты его матчишь как int?

ВВ>>int|string — это у нас такой тип. Он известен в компайл-тайм. Но в рантайм у него может быть одно значение — либо int, либо string. Задача — проверить, что там внутри на самом деле — int или string.

D>Вроде вверху это задача полность решена.
ВВ>>Причем учитывая, что количество комбинаций x|y|z стремится к бесконечности сделать это как-нибудь так, чтобы не пришлось писать проверки на каждую конкретную комбинацию.
D>Это уже другая проблема. Для одной переменой достаточно написать три метода для каждого типа, для двух по три уже 9ть, если какие то вас явно не интересуют, можно использовать обобщения, и выкидывать лишнее.

Что значит "выкидывать лишнее"? Одного этого уже хватает, чтобы убедиться в некоторой "нежизненности" идее. Чем дальше ты идешь, тем ближе ты скатываешься к кортежам. А кортежи в статических языках офигенно негибкая шутка. Я еще касался вопроса, отличается ли int|string от string|int.

ВВ>>Вам нужен пример с утка.КряКря?

D>Да, имено это и нужно.Минимальный пример что бы не пришлось отвлекатся на то что можно опустить.

Я так понял, из моих примеров опустить надо просто все.

Ладно. Статика — это система типов. Это практически синонимы. Нет системы типов, нет статики. В большинстве статических языков систему типов можно обойти, и тогда-то и начинается динамика. Достаточно всего лишь снизить требования к типу. Например, сказать, что все наши конструкторы принадлежат одному единому типу. Или проще:

Это статика:

def tup = (0,1,2);

tup[3] //ошибка компиляции


А это динамика:

def arr = array[0,1,2];

arr[3] //ошибка времени исполнения


А теперь посмотри на свой код и скажи, много ли у тебя "статики".
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 29.04.11 21:07
Оценка: +1
Здравствуйте, dotneter, Вы писали:

ВВ>>>>Когда закончишь — позови.

D>>>Наверное как то так.
D>>>Type X = object -> X
ВВ>>Что такое object? "Любой тип"?
D>да

Значит, это динамика.
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 29.04.11 21:49
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

Ок, я сдался. Толи вы не хотите ничего понимать, то ли я плохо объясняю, но вроде тут насколько все очевидно ...
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: FR  
Дата: 30.04.11 04:36
Оценка: +1
Здравствуйте, dotneter, Вы писали:

D>Ок, я сдался. Толи вы не хотите ничего понимать, то ли я плохо объясняю, но вроде тут насколько все очевидно ...


Вот мне тоже кажется что у тебя в результате получается неуклюжая, неудобная эмуляция динамики на статическом языке,
притом с потерей почти всех преимуществ статики.
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 30.04.11 08:34
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, dotneter, Вы писали:


D>>Ок, я сдался. Толи вы не хотите ничего понимать, то ли я плохо объясняю, но вроде тут насколько все очевидно ...


FR>Вот мне тоже кажется что у тебя в результате получается неуклюжая, неудобная эмуляция динамики на статическом языке,

FR>притом с потерей почти всех преимуществ статики.
Давайте попробуем с вами.
У меня нет никакой эмуляции, это все теже ат (алгебраические типы), только матчинг по конструктору заменен матчингом по типу.
data Either a b
= Left a
| Right b

case x of
     Left _ -> ...
     Right _ -> ...
     

data X = int|string

case x of
    _ :: int -> 
    _ :: string ->


Тоесть все что вы говорите автоматом относится и к ат.
Ат это неуклюжая эмуляция динамики с потерей всех приемуществ статики. Вы это имеете в виду?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: FR  
Дата: 30.04.11 08:52
Оценка:
Здравствуйте, dotneter, Вы писали:


D>Тоесть все что вы говорите автоматом относится и к ат.

D>Ат это неуклюжая эмуляция динамики с потерей всех приемуществ статики. Вы это имеете в виду?

То есть никакого вывода возвращаемого значения, его тип заранее жестко задан?
Тогда не вижу вообще темы для обсуждения у тебя просто получается сахар к обычным АТД в виде неявных конструкторов.
Я не думаю что это сильно что-то упростит, это и так не сложно:
type ret = Int of int | String of string

let foo x = if x = 0 then Int x else String "bar"

let test = function
  | Int x -> printf "%d\n" x
  | String s -> printf "%s\n" s
Re[14]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 30.04.11 08:57
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, dotneter, Вы писали:



D>>Тоесть все что вы говорите автоматом относится и к ат.

D>>Ат это неуклюжая эмуляция динамики с потерей всех приемуществ статики. Вы это имеете в виду?

FR>То есть никакого вывода возвращаемого значения, его тип заранее жестко задан?

Что мешает ему быть выведеным? Выкидываем имя X, и возвращаемся к первому примеру.
let foo x = if x == 0 then 0 else "bar" end
foo :: int -> int | string
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[15]: [Динамик не нужен] Анонимные алгебраические типы.
От: FR  
Дата: 30.04.11 09:02
Оценка:
Здравствуйте, dotneter, Вы писали:

FR>>То есть никакого вывода возвращаемого значения, его тип заранее жестко задан?

D>Что мешает ему быть выведеным? Выкидываем имя X, и возвращаемся к первому примеру.
D>let foo x = if x == 0 then 0 else "bar" end
D>foo :: int -> int | string

Тогда мы получаем разновидность того, что в OCaml называется полиморфный вариант http://www.rsdn.ru/forum/philosophy/4251507.1.aspx
Автор: FR
Дата: 27.04.11

Он по сути ослабляет статическую типизацию http://www.rsdn.ru/forum/decl/4032286.flat.aspx
Автор: Воронков Василий
Дата: 10.11.10
Re[16]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 30.04.11 09:15
Оценка:
Здравствуйте, FR, Вы писали:

FR>Он по сути ослабляет статическую типизацию http://www.rsdn.ru/forum/decl/4032286.flat.aspx
Автор: Воронков Василий
Дата: 10.11.10

Они да, в моем варианте конструкторов нет.

  let foo x = 
  if x = 0 then `MyInt 0 else `MyStr "bar"
  
  
let print = function
  | `MyInt x -> printf "`MyInt = %d\n" x
  | `MyStr1 x -> printf "`MyStr = %s\n" x
print foo 1



Правильно я понимаю что это скомпилируется, и упадет в рантайме?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[17]: [Динамик не нужен] Анонимные алгебраические типы.
От: FR  
Дата: 30.04.11 09:34
Оценка:
Здравствуйте, dotneter, Вы писали:


D>Правильно я понимаю что это скомпилируется, и упадет в рантайме?


Нет будет ошибка компиляции, тип же выводится в print и соответственно он будет требовать `MyInt | `MyStr1 что не включает в
себя возвращаемый foo тип `MyInt | `MyStr. Вот если в print добавить | _ -> printf "unknown\n" то тогда все скомпилируется и
не будет падать, но опечатку `MyStr1 вместо `MyStr компилятор уже нам не найдет.
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 30.04.11 09:40
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Честно говоря, не вижу причин, по которым количество и типы аргументов обязательно должны быть всегда известны статически.

Например?

ВВ>Но даже это и неважно. Если ты строку формата не можешь явно скормить компилятору в виде константы, то он просто не сможет типизировать функцию. Другого пути нет.

Это просто не правда. Функцию можно типизировать по ее параметрам.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[14]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 30.04.11 09:40
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну через заглушку работает, но чем это от варианта отличается

ВВ>А rectypes вообще достаточно стремная штука. К сожалению, она не просто включает рекурсивные типы, а еще и дает по голове тайп-чекеру так, что он начинает пропускать ошибочный код.
Ну это косяк ОКамла. И не говорит ничего плохого о рекурсивных типах как таковых.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[18]: [Динамик не нужен] Анонимные алгебраические типы.
От: dotneter  
Дата: 30.04.11 09:45
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, dotneter, Вы писали:



D>>Правильно я понимаю что это скомпилируется, и упадет в рантайме?


FR>Нет будет ошибка компиляции, тип же выводится в print и соответственно он будет требовать `MyInt | `MyStr1 что не включает в

FR>себя возвращаемый foo тип `MyInt | `MyStr. Вот если в print добавить | _ -> printf "unknown\n" то тогда все скомпилируется и
FR>не будет падать, но опечатку `MyStr1 вместо `MyStr компилятор уже нам не найдет.
Ну так, не делать _ -> и не будет никакой динамики. Если и в моем случае так писать, то тогда тоже непонятно что там на входе, я бы заставлял при использовании _ -> явно описывать тип функции, тогда и проблем никаких.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[14]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 30.04.11 13:54
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Но даже это и неважно. Если ты строку формата не можешь явно скормить компилятору в виде константы, то он просто не сможет типизировать функцию. Другого пути нет.

WH>Это просто не правда. Функцию можно типизировать по ее параметрам.

Ну так тип единственного параметра printf и вычисляется в компайл-тайме на основе *значения* строки формата.
Re[15]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 30.04.11 14:03
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Ну через заглушку работает, но чем это от варианта отличается

ВВ>>А rectypes вообще достаточно стремная штука. К сожалению, она не просто включает рекурсивные типы, а еще и дает по голове тайп-чекеру так, что он начинает пропускать ошибочный код.
WH>Ну это косяк ОКамла. И не говорит ничего плохого о рекурсивных типах как таковых.

Речь тут в общем-то не о рекурсивных типах вообще, а конкретно о циклических типах. И в теории они должны быть решаемы. Но на практике оказывается, что в существующие системы типов чистые рекурсивные типы не очень вписываются. В том же Хаскеле, например, изорекурсивный тип выразить можно, а с эквирекурсивный, а соответственно, и циклический, АФАИК нет.
Re[15]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 30.04.11 15:08
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну так тип единственного параметра printf и вычисляется в компайл-тайме на основе *значения* строки формата.

Один? Правда? А что тогда в строку форматирования то подставляется?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[16]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 30.04.11 16:54
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

ВВ>>Ну так тип единственного параметра printf и вычисляется в компайл-тайме на основе *значения* строки формата.

WH>Один? Правда? А что тогда в строку форматирования то подставляется?

Да, теперь я понимаю, почему меня не понимают

Параметр действительно один. Я тебе скажу больше — в OCaml, F#, Haskell да и в Ela в принципе невозможно написать функцию, которая принимает больше одного параметра.
Вот, посмотри: http://blogs.msdn.com/b/vorov/archive/2011/04/19/10155122.aspx
Re[17]: [Динамик не нужен] Анонимные алгебраические типы.
От: WolfHound  
Дата: 30.04.11 18:18
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Параметр действительно один. Я тебе скажу больше — в OCaml, F#, Haskell да и в Ela в принципе невозможно написать функцию, которая принимает больше одного параметра.

Типа языки только ими и ограничиваются
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[18]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 30.04.11 18:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

ВВ>>Параметр действительно один. Я тебе скажу больше — в OCaml, F#, Haskell да и в Ela в принципе невозможно написать функцию, которая принимает больше одного параметра.

WH>Типа языки только ими и ограничиваются

Вроде бы речь была, процитирую, про "ML-ный printf"

ЗЫ. А вообще вместо того, чтобы в очередной раз спорить на увлекательнейшую тему динамика вс. статика лучше взять какие-нибудь задачки отсюда да посмотреть как они решаются на статике и динамике. Заодно могли бы расширить страницу Немерле примерами кода, коих там сейчас вообще нет.
Re[5]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 03.05.11 09:17
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, maxkar, Вы писали:


M>>Да, неплохо. Только вот мне не нравится, что это шаблон. Я хочу именно функцию. Чтобы ее можно было куда-нибудь еще передавать, например.


FR>Этот шаблон порождает полноценную функцию полностью совпадающую по типу с ее функцией аргументом, с ней можно делать все что можно делать с любой другой функцией. Тут чуть разъясню, шаблоны D в отличии от шаблонов C++ могут порождать любые типы, а не только структуры/классы или функции.


Я не про то. Я сам exceptionProtect хочу иметь как first-class object. То, что его результат является функцией — понятно. Например, можно было бы exceptionProtect в Array.map передать или куда-нибудь еще. Другой "шаблон" построить в рантайме и т.п. И вот как раз полноценной работы с типами мне хватило бы. Причем передачи AST мне ни в один шаблон не нужно. Туда передаются значения разной природы. Это могут быть объекты, это могут быть функции и на выходе как-то строится тип результата. Т.е. "более типизированная" "динамика". В принципе, возможность работы таких "шаблонов" в рантайме упирается в необходимость хорошего RTTI, возможность порождать описания типов в рантайме и "динамический" способ вызова функции.
Re[5]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 03.05.11 09:33
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, maxkar, Вы писали:


M>>Потому что изначально метод предназначался для защиты функции, строящейся по конфигу во время исполнения, а не во время написания кода. Что-то вроде

WH>Ну строится.
WH>Ну по конфигу.
WH>Дальше то что?
WH>Почему у функции тип не известен?

Известен только в рантайме этот тип. Потому что берется из конфига. При этом тип может быть не "точный" (требуемый реализациями), а "приводимый" к требуемому. Например, возможно следующее:
const f : Function = function(a : int, b : int = 3) : int {
  return a + b;
}
f(3);
f(5, 6);

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

M>>Оно строит новый объект, имеющий те же поля (с теми же значениями) но функции обернуты и защищены. Полезно на инфраструктурном уровне, например, в dependency injection framework. Ну или любой другой внешней конфигурации модулей и межмодульного взаимодействия.

WH>Давай конкретный пример.
const config : XML = loadConfig(xml);
const services : Function = parseServices(config);
const protectedService : Function = serviceProtect(services, callMethod(serivces, 'application', 'fatal-error'));
const someObject : FirstType = protectedService('get', 'some', 'strange', 'value');
const otherObject : SecondType = protectedService('convert', 'wrap-errors', someObject);
protectedService('call-service-expect-xml', 'service-name', 'operation-name', {fieldA : someObject.a, fieldB : otherObject.a}, {success : handleCallSuccess, await : waitCallHandler});
protectedService('show-dialog', 'about-dialog', protectedServices);
protectedService('show-dialog', 'format-drive-dialog', protectedServices, 'c:');

Вот что-то в подобном роде используется в реальном коде. Обработчики 'about-dialog', 'format-drive-dialog' и т.п. могут находиться в различных подгружаемых модулях, описываются в конфиге. На самом деле чуть еще сложнее, но это не важно. Сервисы передаются в диалоги, так как эти же сервисы предоставляют интерфейс к графической подсистеме, менеджер окон, те же вызовы сервисов и т.п. При желании можно "модифицировать" сервис и передавать уже его в различные диалоги. Все подобные обработчики вообще не имеют никакого глобального состояния и привязок, им достаточно входных аргументов этого вызова.

Словить интеграционную ошибку в рантайме и поправить вызов для меня проще (и быстрее), чем писать и поддерживать типизированную стуктуру заглушек для контроля типов контейнера. Ну и плюс сам язык не поддерживает статическую типизацию в достаточной степени, так что я вообще ничего не теряю.
Re[6]: Анонимные алгебраические типы. Более сложный случай.
От: WolfHound  
Дата: 03.05.11 10:02
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Известен только в рантайме этот тип.

То, что ты так сделал это одно.
Но то, что тип нельзя узнать на этапе компиляции... прости не верю.

M>Потому что берется из конфига.

Что берется из конфига?

M>Второй аргумент к функции может появиться в процессе эволюции. Весь код, который работал ранее с функцией от одного аргумента, будет с ней работать даже без перекомпиляции. А вот новая функциональность будет использовать и второй аргумент.

Что-то ты странное мутишь.

M>Словить интеграционную ошибку в рантайме и поправить вызов для меня проще (и быстрее), чем писать и поддерживать типизированную стуктуру заглушек для контроля типов контейнера.

Как я понял у тебя там какой-то IoC происходит.
Так вот я такое даже на С++ делал.
Динамика тут нужна как рыбке зонтик.
А что за заглушки тебе понадобились я так и не понял.

M>Ну и плюс сам язык не поддерживает статическую типизацию в достаточной степени, так что я вообще ничего не теряю.

Это проблема языка.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.05.11 15:13
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Запишешь мне какой будет тип у такой функции?


ВВ>
ВВ>let out x = write x $ out
ВВ>


ВВ>Аналог на ДжаваСкрипте:


ВВ>
ВВ>function out (x) {
ВВ>   write(x);
ВВ>   return out;
ВВ>}
ВВ>


ВВ>Когда закончишь — позови.

  Out[T](x : T) : T // T -> T
  {
    Write(x);
    x
  }
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.05.11 15:24
Оценка: +2
Здравствуйте, VladD2, Вы писали:

ВВ>>Аналог на ДжаваСкрипте:


ВВ>>
ВВ>>function out (x) {
ВВ>>   write(x);
ВВ>>   return out;
ВВ>>}
ВВ>>


ВВ>>Когда закончишь — позови.

VD>
VD>  Out[T](x : T) : T // T -> T
VD>  {
VD>    Write(x);
VD>    x
VD>  }
VD>


не оно. Надо вернуть не аргумент, а саму функцию
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: hardcase Пират http://nemerle.org
Дата: 03.05.11 15:29
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Когда закончишь — позови.

VD>
VD>  Out[T](x : T) : T // T -> T
VD>  {
VD>    Write(x);
VD>    x
VD>  }
VD>



Неа. Там рекурсивный тип. Точный аналог на Nemerle записать можно только так:
    def o(x)
    {
      Write(x);
      o
    }
    _ = o(1)(2)(3);


Компилятор же на это расскажет про циклический тип
/* иЗвиНите зА неРовнЫй поЧерК */
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.05.11 15:33
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Неа. Там рекурсивный тип. Точный аналог на Nemerle записать можно только так:

H>
H>    def o(x)
H>    {
H>      Write(x);
H>      o
H>    }
H>    _ = o(1)(2)(3);
H>


H>Компилятор же на это расскажет про циклический тип


А какой практический смысл этой хрени? По обсуждать в Философии?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Динамик не нужен] Анонимные алгебраические типы.
От: snoɯʎuouɐ  
Дата: 03.05.11 16:34
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>+ Полиморфные варианты, все конструкторы которых к единой хербрандовой вселенной


Всё-таки Эрбрановой. В честь Жака Эрбрана.
Re[2]: [Динамик не нужен] Анонимные алгебраические типы.
От: artelk  
Дата: 03.05.11 16:41
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

Да простит меня топикстартер, попробую изложить свою версию.
let foo x = if x==0 then 0 else "hi"
foo :: int -> int | string

Ф-я возвращает анонимный АТД. Чтобы выцепить само значение, требуется сделать матчинг с обоими вхождениями, что необходимо для обеспечения типобезопасности.
Различать int|string и string|int смысла не имеет.

Перегрузка функций:
let bar x = x + 1
bar :: int -> int
let bar x = x + "\n"
bar :: string -> string


Обнаружив такую перегрузку компилятор должен позволить вызвать функцию bar с аргументом int|string. Ее результатом будет опять-таки int|string.
Кроме того, если на момент компиляции фактический тип x известен, то тип результата может быть выведен более точно:
let z1 = bar 1
z1 :: int
let z2 = bar "hi"
z2 :: string


Аналогично, если ф-я bar задана для класса типов (например Num):
bar :: (Num a) => a -> a
let bar x = x * x

, то ее можно вызвать для, например, int|double и получить int|double. Но если "точный" тип параметра известен, то и тип результата можно вывести поточнее.

Вернемся к foo:
let z1 = foo 0
let z2 = foo 1

Какие типы у z1 и z2? Если определение foo известно на момент компиляции, то компилятор может вывести, что
z1 :: int
z2 :: string

И матчинга для них уже не потребуется.
Фактически, это эквивалентно тому, что компилятор переписывает foo во что-то подобное:
let foo 0 = 0
let foo x {where x != 0} = "hi"

и дальше поступает по аналогии с перегрузками bar.

По большому счету, определение foo может и не потребоваться в момент его вызова, если в момент компиляции foo компилятор добавляет необходимую метаинформацию о зависимости типа результата от значений (и типов) параметров. Если полный анализ ее кода не возможен или слишком сложен то он, возмозно, даже и не нужен — достаточно сделать подсказки для подмножества случаев, которые видны компилятору "невооруженным взглядом".

ВВ>Системы типов консервативны, они не пытаются доказать правильность программы, они доказывают ее возможную неправильность. Код вида foo x * foo y возможно неправильный (но частный случай foo 0 * foo 0 — правильный). Исходя из того, что выражение foo x * foo y в принципе может быть неправильным, система типов этот код не пропустит.


Допустим, для строк и целых определен оператор +.
let f x y = foo x + foo y
f :: int -> int -> int|string

тут возможны, по крайней мере, такие варианты:
1. Статическая система типов определение такой ф-ии не пропустит, т.к. int+string не определен.
2. Система типов ее пропустит. В рантайме будет кидаться что-то вроде NotImplementedException для f 0 1, f 1 0 и т.п. Возникает вопрос о "статичности" этой системы.
3. Компилятор сгенерирует code contract для этой ф-ии и будет его статически проверять и не давать вызвать эту ф-ю, пока ему не докажешь, что (x==0 && y==0)||(x!=0 && y!=0). Все статически типизированно.



В принципе, перегрузка ф-ий не дружит с каррингом. Можно попробовать побороть опять таки использованием таких анонимных АТД. Например,
f :: a -> a
let f x = x
f :: a -> b -> b
let f x y = y

//Результат:
f :: a -> a|(b->b)

и, на основании контекста, выводить, какую реализацию вызывать. Плюс придумать синтаксис для разрешения неоднозначностей, если возникнут.

ВВ>Есть два варианта:

ВВ>+ Функция, тип которой зависит от [типа] параметров
ВВ>+ Функция, тип которой зависит от значений параметров

ВВ>Первый вариант в статике возможен:

ВВ>printf "%d+%d=%d" 2 2 (2+2)

ВВ>Второй — нет:

ВВ>let myPrint fmt = printf fmt ...?

Не очень понятно. Возможно, имеется ввиду такой случай:
let myPrint fmt = \... -> printf fmt ...

Т.е. в зависимости от значения fmt тип "myPrint fmt" будет разный:
для "%d": int -> ()
для "%d%s": int -> string -> ()
так?

Если fmt статически известен, то вывести можно сразу. Если нет, то придется, видимо, мудрить с рекурсивными типами (что-то вроде type UniversalFuncType = a->() | b->UniversalFuncType) и матчить.
В принципе, если формат приходит не извне (пользовательский ввод, файл и т.п.), а формируется в коде, то компилятор кое-какую дополнительную информацию может и получить.
Эх, доберусь я до зависимых типов иии...
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 04.05.11 05:46
Оценка:
Здравствуйте, VladD2, Вы писали:


ВВ>>Когда закончишь — позови.

VD>
VD>  Out[T](x : T) : T // T -> T
VD>  {
VD>    Write(x);
VD>    x
VD>  }
VD>


Это совсем не то
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 04.05.11 06:00
Оценка:
Здравствуйте, VladD2, Вы писали:

H>>Компилятор же на это расскажет про циклический тип

VD>А какой практический смысл этой хрени? По обсуждать в Философии?

Например, Y-комбинатор:

\f -> (\x -> f (x x)) (\x -> f (x x))


Кстати, out в его обобщенном варианте rec:

let rec f x = f x $ rec f


достаточно полезен. Можно, к примеру писать так:

rec writen "Line1" "Line2"


Вместо:

writen "Line1" $ writen "Line2"
Re[14]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 10:43
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Например, Y-комбинатор:


ВВ>
ВВ>\f -> (\x -> f (x x)) (\x -> f (x x))
ВВ>


И на фиг он уперся в реальной то работе?

ВВ>Кстати, out в его обобщенном варианте rec:


ВВ>
ВВ>let rec f x = f x $ rec f
ВВ>


ВВ>достаточно полезен.


На фиг он не уперся. Просто ты совсем зафилосовствовался. А есть еще такой не маловажный принцип дизайна как простота.

ВВ>Можно, к примеру писать так:


ВВ>
ВВ>rec writen "Line1" "Line2"
ВВ>


ВВ>Вместо:


ВВ>
ВВ>writen "Line1" $ writen "Line2"
ВВ>


А можно писать так:
writen("Line1\nLine2")

или так
writen("Line1", "Line2")

или так
writen("Line1");
writen("Line2");

Для решаемой задачи это ровным счетом ничего не изменит. Так что по принципу бритвы Оккама — в топку.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 04.05.11 13:54
Оценка: +1
Здравствуйте, VladD2, Вы писали:

ВВ>>
ВВ>>\f -> (\x -> f (x x)) (\x -> f (x x))
ВВ>>

VD>И на фиг он уперся в реальной то работе?

Что ты называешь "реальной работой"? Мейнстрим что ли?
Я вот вас не понимаю, честно говоря. Лямбда-исчисление вам в "реальной работе" не требуется, а вот без макросов никуда, да.

Большинству в "реальной работе" ну нужны ни ФП, ни МП, ни прочие страшные буквы. И что теперь, на бейсике писать?

ВВ>>Кстати, out в его обобщенном варианте rec:

ВВ>>
ВВ>>let rec f x = f x $ rec f
ВВ>>

ВВ>>достаточно полезен.
VD>На фиг он не уперся. Просто ты совсем зафилосовствовался. А есть еще такой не маловажный принцип дизайна как простота.

Простота чего? Системы типов? Не уверен, что это плюс. Как можно одновременно затаптывать динамику и ратовать за простую систему типов? Которая сгодится только факториалы писать.
Или речь о простоте языка? Так куда уж проще-то. Есть функции, все функции принимают один аргумент, есть операция применения функции. Все.
Re[16]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 14:21
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Что ты называешь "реальной работой"? Мейнстрим что ли?


Написание кода для решения реальных задач.

ВВ>Я вот вас не понимаю, честно говоря. Лямбда-исчисление вам в "реальной работе" не требуется, а вот без макросов никуда, да.


Лямбда-исчисления не требуются (это теория), а лямбды полезны... а Y-комбинаторы бесполезны. Единственное где я их видел — это тесты компиляторов. Слышал что в C# особо извращенные товарищи решают ими проблему отсутствия локальных функций (объявляют рекурсивную функцию по месту).

ВВ>Большинству в "реальной работе" ну нужны ни ФП, ни МП, ни прочие страшные буквы. И что теперь, на бейсике писать?


Это неверная постановка вопроса. Они не ненужные, а неизвестны и потому не применяются. А вот о существовании Y-комбинаторов многим известно. Но применять их на практике смысла нет. Это не более чем забавное проявление теории.

В общем, чтобы фича применялась мало ее придумать и реализовать. Недостаточно даже если фича будет круто выглядеть. Нужно еще чтобы она была нужна на практике. Если она на практике ничего не дает, то и фича эта не нужна.

Что касается Y-комбинаторов, то они как бы даются в нагрузку за поддержку лямбд. Ничего специально делать для их появления не надо.

А вот то о чем ты говоришь требует. Но бенефитов от этого пока не видно. Так стоит ли вводить новую сущность, если в ней нет необходимости?

ВВ>Простота чего? Системы типов?


Простота языка. Система типов — это его часть.

ВВ>Не уверен, что это плюс. Как можно одновременно затаптывать динамику и ратовать за простую систему типов?


Важно иметь возможность решать реальные пробелмы. Если есть приемлемые средства решения проблемы, то еще одного способа ее решить не нужно.

ВВ>Которая сгодится только факториалы писать.

ВВ>Или речь о простоте языка? Так куда уж проще-то. Есть функции, все функции принимают один аргумент, есть операция применения функции. Все.

Ну, как видишь не очень то все просто. Уж лучше оперировать object-ом, чем усложнять систему типов ради прикольной безделицы.

Скажем так. Я понимаю что может дать зависимые или уникальные типы. Не уверен, что то что они дадут оправдает усложнение языка, но все же понимаю. Тут же я пока что не понимаю зачем это нужно. Если разумный объяснений не найдется, то я буду склонен считать, что исключительно для пенесометрии.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Техническая поправка
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 18:26
Оценка:
Здравствуйте, deniok, Вы писали:

D>Лямбды забыл спереди

D>
D>\f g h -> f `mapSum` g `mapSum` h :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> a1 | a2 | a3 -> b1 | b2 | b3
D>

D>но идея ясна.

Кабздец! И потом люди спрашивают почему мало кто хочет писать на хаскеле.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Анонимные алгебраические типы. Более сложный случай.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 18:34
Оценка:
Здравствуйте, maxkar, Вы писали:

M>
M>const f : Function = function(a : int, b : int = 3) : int {
M>  return a + b;
M>}
M>f(3);
M>f(5, 6);
M>


Что это за язык?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Анонимные алгебраические типы. Более сложный случай.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 18:35
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Вот что-то в подобном роде используется в реальном коде. Обработчики 'about-dialog', 'format-drive-dialog' и т.п. могут находиться в различных подгружаемых модулях, описываются в конфиге.


Программирование на конфигах? А ради чего?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 18:40
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.


А список параметров ты тоже в рантайме формировать будешь?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 18:44
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну так тип единственного параметра printf и вычисляется в компайл-тайме на основе *значения* строки формата.


В нормальных языках вывод типов может быть произведен и без строки формата. А вот в выводе типов по строке формата смысла нет. Вообще нет!

Ну, а написать код который возьмет типы параметров и по ним построить динамическую проверку строки формата задача не сложная.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.11 19:00
Оценка:
Здравствуйте, FR, Вы писали:

FR>>>То есть никакого вывода возвращаемого значения, его тип заранее жестко задан?

D>>Что мешает ему быть выведеным? Выкидываем имя X, и возвращаемся к первому примеру.
D>>let foo x = if x == 0 then 0 else "bar" end
D>>foo :: int -> int | string

FR>Тогда мы получаем разновидность того, что в OCaml называется полиморфный вариант http://www.rsdn.ru/forum/philosophy/4251507.1.aspx
Автор: FR
Дата: 27.04.11

FR>Он по сути ослабляет статическую типизацию http://www.rsdn.ru/forum/decl/4032286.flat.aspx
Автор: Воронков Василий
Дата: 10.11.10


Думаю, что он имеет в виду другое. Он видимо имеет в виду вывод безымянного АлгТД по использованию внутри функции. При наличии функции генератора и функции потребителя соответствие типов можно будет проверить явно.

В Окамле же речь, как я понимаю, идет об одном, большом, расширяемомо АлгТД расширяемость которого и ослабляет типизацию.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 05.05.11 11:01
Оценка: +1
Здравствуйте, VladD2, Вы писали:

ВВ>>Ну так тип единственного параметра printf и вычисляется в компайл-тайме на основе *значения* строки формата.

VD>В нормальных языках вывод типов может быть произведен и без строки формата. А вот в выводе типов по строке формата смысла нет. Вообще нет!
VD>Ну, а написать код который возьмет типы параметров и по ним построить динамическую проверку строки формата задача не сложная.

Замени "нормальные языки" на "Си-подобные". Выводить по типу параметров можно, если функция принимает несколько параметров. Если в языке вообще нет средств для объявления функций, принимающих несколько параметров, то вывод по формату — единственный по сути вариант. Некрасивость здесь только в том, что формат выглядит как строка, но на самом деле это не строка. А из-за этого возникает та же проблема, что и с $-строками в Немерле — даже в ресурсник не положишь.
Re[12]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 05.05.11 11:03
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.

VD>А список параметров ты тоже в рантайме формировать будешь?

А списка параметров и нет. По сути есть лишь последовательные вызовы функции. Ты можешь вызвать функцию так: printf(x)(y) а можешь так: printf(x)(y)(z) — и в обоих случаях произойдет сатурация. Потребуется ли тебе вызвать функцию еще раз или не потребуется — вполне может определяться в рантайме.
Re[17]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 05.05.11 11:28
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Что ты называешь "реальной работой"? Мейнстрим что ли?

VD>Написание кода для решения реальных задач.

Реальной задачей может быть и разработка системы исчисления на основе парочки комбинаторов. Или доказательство теорем. Или написание примерчиков для rosettacode. Так что define "реальная".
Для большинства "реальные задачи" с разработкой компиляторов и веб-фреймворков тоже не связаны.

ВВ>>Я вот вас не понимаю, честно говоря. Лямбда-исчисление вам в "реальной работе" не требуется, а вот без макросов никуда, да.

VD>Лямбда-исчисления не требуются (это теория), а лямбды полезны... а Y-комбинаторы бесполезны.

Вот эту фразу я вообще не понимаю. Быть может, есть какие-то другие комбинаторы, которые ты считаешь полезными? Или что ты называешь "лямбдами"?

ВВ>>Большинству в "реальной работе" ну нужны ни ФП, ни МП, ни прочие страшные буквы. И что теперь, на бейсике писать?

VD>Это неверная постановка вопроса. Они не ненужные, а неизвестны и потому не применяются. А вот о существовании Y-комбинаторов многим известно. Но применять их на практике смысла нет. Это не более чем забавное проявление теории.

Ага, а еще одним забавным проявлением теории являются системы типов, в основании которых лежит типизированное лямбда-исчисление.

VD>В общем, чтобы фича применялась мало ее придумать и реализовать. Недостаточно даже если фича будет круто выглядеть. Нужно еще чтобы она была нужна на практике. Если она на практике ничего не дает, то и фича эта не нужна.

VD>Что касается Y-комбинаторов, то они как бы даются в нагрузку за поддержку лямбд. Ничего специально делать для их появления не надо.

(Я понял, тебе не нравятся Y-комбинаторы. Приведи тогда три своих любимых комбинатора, их и обсудим).
По существу — в рамках нетипизированного лямбда-исчисления делать ничего не надо. В рамках типизированного — чтобы записать его именно так, как я, а не через жопу, как это обычно делается, должна быть поддержа эквирекурсивных типов, о чем мы, собственно, тут и говорим.

VD>А вот то о чем ты говоришь требует. Но бенефитов от этого пока не видно. Так стоит ли вводить новую сущность, если в ней нет необходимости?


А я никого не убежаю что-то вводить. К тому же сделать это, подозреваю, весьма непросто. Речь всего лишь о том, что реальные, а не сферические, системы типов все же весьма ограничены, и динамика, которая позволяет записывать все as is, как оно и выглядит в "учебниках", часто смотрится на их фоне весьма выгодно.

Что до полезности. Ну я сталкивался с необходимости циклических типов при программировании в CPS-стиле. Да, в принципе их отсутствие как-то обходится, но код выглядит менее наглядно и замусоривается.

ВВ>>Простота чего? Системы типов?

VD>Простота языка. Система типов — это его часть.

Сложное утверждение на самом деле. Вот положим есть язык — Хаскель. Хаскель поддерживает higher-rank polymorphism. А есть система типов Хаскеля. В ней higher-rank polymorphism является undecidable.

ВВ>>Не уверен, что это плюс. Как можно одновременно затаптывать динамику и ратовать за простую систему типов?

VD>Важно иметь возможность решать реальные пробелмы. Если есть приемлемые средства решения проблемы, то еще одного способа ее решить не нужно.

Все это слишком общие понятия, чтобы ими оперировать. Что такое "реальные проблемы", какие средства мы считаем "приемлимыми", а какие — нет? Это все весьма субьективно.
Вот перечисли три реальные проблемы, которые ты решал последнее время. В ответ — перечислю свои (те, за которые деньги платят, а не "для души").

ВВ>>Которая сгодится только факториалы писать.

ВВ>>Или речь о простоте языка? Так куда уж проще-то. Есть функции, все функции принимают один аргумент, есть операция применения функции. Все.
VD>Ну, как видишь не очень то все просто. Уж лучше оперировать object-ом, чем усложнять систему типов ради прикольной безделицы.

В рамках untyped lambda calculus, которая, как говорится, есть отец и матерь, все действительно именно так просто. Функции, применение функций — больше ничего не надо. А вот в рамках typed...

VD>Скажем так. Я понимаю что может дать зависимые или уникальные типы. Не уверен, что то что они дадут оправдает усложнение языка, но все же понимаю. Тут же я пока что не понимаю зачем это нужно. Если разумный объяснений не найдется, то я буду склонен считать, что исключительно для пенесометрии.


Ну по крайней мере заметен прогресс. Раньше ты говорил, что зависимые типы не нужны, ибо есть макросы, и все это можно и нужно делать на макросах. Теперь ты видишь пользу, но усложнение языка считаешь неоправданным. Что ж, остался еще один шаг
Re[17]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.05.11 13:49
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Замени "нормальные языки" на "Си-подобные". Выводить по типу параметров можно, если функция принимает несколько параметров. Если в языке вообще нет средств для объявления функций, принимающих несколько параметров, то вывод по формату — единственный по сути вариант. Некрасивость здесь только в том, что формат выглядит как строка, но на самом деле это не строка.


Дело не в Си-подобности, а в алгоритмах вывода типов.

ВВ>А из-за этого возникает та же проблема, что и с $-строками в Немерле — даже в ресурсник не положишь.


В Немерле это ни разу не проблема. Я на самых ранних этапах знакомства с Немрелом реализовал макрос локализации приложений. Он сам находил такие строки и строил по ним файл локализации который потом можно было заменить. Думаю будет не сложно нагуглить ссылку на эту реализацию.

Надо понимать, что Немерле и $-строки, и "функция" printf — это макросы. А макросы вольны анализировать свои параметры и переписывать код как угодно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.05.11 13:50
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, VladD2, Вы писали:


ВВ>>>Более практической задачей был — "динамический" ML-ный printf, для которого строку формата можно формировать в рантайме.

VD>>А список параметров ты тоже в рантайме формировать будешь?

ВВ>А списка параметров и нет. По сути есть лишь последовательные вызовы функции.


Это булшит. Ты в коде как писать будешь?

ВВ>Ты можешь вызвать функцию так: printf(x)(y) а можешь так: printf(x)(y)(z) — и в обоих случаях произойдет сатурация. Потребуется ли тебе вызвать функцию еще раз или не потребуется — вполне может определяться в рантайме.


Еще раз задаю вопрос. Ты этот код будешь писать в исходном файле или ты как-то чудесным образом будешь формировать список аргументов в рантайме?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: [Динамик не нужен] Анонимные алгебраические типы.
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.05.11 14:02
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Реальной задачей может быть и разработка системы исчисления на основе парочки комбинаторов. Или доказательство теорем. Или написание примерчиков для rosettacode. Так что define "реальная".


Это треп. Для описанных задач есть специально предназначенные для этого решения.

ВВ>Для большинства "реальные задачи" с разработкой компиляторов и веб-фреймворков тоже не связаны.


Это к делу не относится. В любой программе потребуются вызовы функций и почти в любой пригодились бы макросы и лямбды. Мне же интересно где могут пригодиться описываемые извращения?

ВВ>Ага, а еще одним забавным проявлением теории являются системы типов, в основании которых лежит типизированное лямбда-исчисление.


Таких систем типов, кстати нет. Точнее все зависит от интертрепации термина "в основании". Но на практике упомянутая теория используется только в общих чертах. А системы типов реальных языков сильно от нее отличаются. В прочем, это с любой теорией так. Теория дает общие идеи, а практика их эксплуатирует в нужном контексте.

ВВ>(Я понял, тебе не нравятся Y-комбинаторы. Приведи тогда три своих любимых комбинатора, их и обсудим).

ВВ>По существу — в рамках нетипизированного лямбда-исчисления делать ничего не надо. В рамках типизированного — чтобы записать его именно так, как я, а не через жопу, как это обычно делается, должна быть поддержа эквирекурсивных типов, о чем мы, собственно, тут и говорим.

Мужик, ты говоришь глупость. С точки зрения теории, нетипизированное лямбда-исчисление выводится из типизированного путем введения одного АлгТД описывающего объединение всех типов. Так что все следствия что можно вывести из нетипизированного лямбда-исчисления точно так же можно вывести из типизированного.

Вопрос только в том, что в теории теория и практика одинаковы, а на практике — нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 05.05.11 14:32
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Реальной задачей может быть и разработка системы исчисления на основе парочки комбинаторов. Или доказательство теорем. Или написание примерчиков для rosettacode. Так что define "реальная".

VD>Это треп. Для описанных задач есть специально предназначенные для этого решения.

Треп — это рассуждение о "реальных задач" без всяких попыток хоть как-то это конкретизировать.

ВВ>>Для большинства "реальные задачи" с разработкой компиляторов и веб-фреймворков тоже не связаны.

VD>Это к делу не относится. В любой программе потребуются вызовы функций и почти в любой пригодились бы макросы и лямбды. Мне же интересно где могут пригодиться описываемые извращения?

Какие извращения? Каррированные функции? Комбинаторы? Эквирекурсия в типах?

ВВ>>Ага, а еще одним забавным проявлением теории являются системы типов, в основании которых лежит типизированное лямбда-исчисление.

VD>Таких систем типов, кстати нет. Точнее все зависит от интертрепации термина "в основании". Но на практике упомянутая теория используется только в общих чертах. А системы типов реальных языков сильно от нее отличаются. В прочем, это с любой теорией так. Теория дает общие идеи, а практика их эксплуатирует в нужном контексте.

Ну как же нет. Для функциональных языков системы типов самым явным образом на типизированном лямбда-исчислении и строится. Для императивных — да, основание весьма косвенно. Но причем тут императивные языки?

ВВ>>(Я понял, тебе не нравятся Y-комбинаторы. Приведи тогда три своих любимых комбинатора, их и обсудим).

ВВ>>По существу — в рамках нетипизированного лямбда-исчисления делать ничего не надо. В рамках типизированного — чтобы записать его именно так, как я, а не через жопу, как это обычно делается, должна быть поддержа эквирекурсивных типов, о чем мы, собственно, тут и говорим.

VD>Мужик, ты говоришь глупость. С точки зрения теории, нетипизированное лямбда-исчисление выводится из типизированного путем введения одного АлгТД описывающего объединение всех типов. Так что все следствия что можно вывести из нетипизированного лямбда-исчисления точно так же можно вывести из типизированного.


Если ты о том, что нетипизированное лямбда-исчисление можно рассматривать как частный случай типизированного — то да, это в принципе верно. Только я не о том. А о том, что типизированное лямбда-исчисление это сферический конь. Реальные же системы типов весьма ограничены. Мы же говорили о том, что нужно в языке, чтобы писать функции-комбинаторы, какие в голову придут? В динамическом — ничего кроме функций не нужно. В статическом — надо "излишне усложнять" систему типов, как ты выражаешься.

VD>Вопрос только в том, что в теории теория и практика одинаковы, а на практике — нет.


Мысль, конечно, верная, но к чему это?
Re[14]: [Динамик не нужен] Анонимные алгебраические типы.
От: Воронков Василий Россия  
Дата: 05.05.11 14:35
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>А списка параметров и нет. По сути есть лишь последовательные вызовы функции.

VD>Это булшит. Ты в коде как писать будешь?

Так и буду писать. Функций, принимающих несколько аргументов просто нет. И это не булшит. И, кстати, это весьма сильно меняет все.

ВВ>>Ты можешь вызвать функцию так: printf(x)(y) а можешь так: printf(x)(y)(z) — и в обоих случаях произойдет сатурация. Потребуется ли тебе вызвать функцию еще раз или не потребуется — вполне может определяться в рантайме.

VD>Еще раз задаю вопрос. Ты этот код будешь писать в исходном файле или ты как-то чудесным образом будешь формировать список аргументов в рантайме?

Легко:

let printf' = printf fmtString x y

let _ | <some condition> = printf' z
| else = printf'
Re[7]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 06.05.11 13:01
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, maxkar, Вы писали:


VD>Что это за язык?


Actionscript 3.0 Диалект ECMAScript с типами и классическими объектами (наследование, интерфейсы и т.п.).
Re[7]: Анонимные алгебраические типы. Более сложный случай.
От: maxkar  
Дата: 06.05.11 13:21
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, maxkar, Вы писали:


M>>Вот что-то в подобном роде используется в реальном коде. Обработчики 'about-dialog', 'format-drive-dialog' и т.п. могут находиться в различных подгружаемых модулях, описываются в конфиге.


VD>Программирование на конфигах? А ради чего?


Пока не программирование. Там циклов нет, а только декларативно описывается "дерево" сервисов. Крупных целей две:
1. Изначально все это разрабатывалось под динамическую загрузку диалогов (модулей). Т.е. что-то подгружается только при первом использовании. Приложение — web, flash, так что заставлять пользователю на плохих каналах все грузить не очень хорошо. Ну и наш трафик жалко (считали, много выходит).
2. Отвязка от "глобальных" переменных. Например, диалог должен иметь доступ, например, к показу/скрытию попапов, новых диалоговых окон и т.п. Тот же диалог при этом может запрашивать какие-то данные из приложения, вызывать сервисы и т.п. Я рассматривал типизированные интерфейсы вроде showAboutDialog(aboutDialogDeps : IAboutDialogDeps), но не понравилось. Где-то параметров большое число получалось. Много писанины для каждого модуля в описании его зависимостей и в написании "реализации" этого интерфейса. При существующей схеме я могу просто "ограничить" существующее подмножество "основных" сервисов. Могу в конфиге на входе в модуль (защита от опечаток), могу при передаче в вызов (защита от злонамеренных модулей). Да и возникают проблемы, где размещать интерфейс вызова этого модуля (см. пункт 1). Динамику запускать и проверять нужно, но на интерфейсах я бы тоже запускал и проверял этот же вызов, так что потерь особых нет.

Ну и еще для одного из модулей изначально предусматривалось несколько различных реализаций (для различных площадок), так что что-нибудь конфигурировать все равно пришлось бы.
Re[8]: Анонимные алгебраические типы. Более сложный случай.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.05.11 18:21
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Пока не программирование. Там циклов нет, а только декларативно описывается "дерево" сервисов. Крупных целей две:...

M>Ну и еще для одного из модулей изначально предусматривалось несколько различных реализаций (для различных площадок), так что что-нибудь конфигурировать все равно пришлось бы.

Ну, то есть вы сами выбрали проектное решение которое подсадило вас на динамику. При этом задача в общем-то решалась и статически?

Получается, что вы просто не нашли красивого статического решения и прибегли к динамике. Все остальное уже следствие.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Анонимные алгебраические типы. Более сложный случай.
От: FR  
Дата: 10.05.11 09:46
Оценка:
Здравствуйте, maxkar, Вы писали:

FR>>Этот шаблон порождает полноценную функцию полностью совпадающую по типу с ее функцией аргументом, с ней можно делать все что можно делать с любой другой функцией. Тут чуть разъясню, шаблоны D в отличии от шаблонов C++ могут порождать любые типы, а не только структуры/классы или функции.


M>Я не про то. Я сам exceptionProtect хочу иметь как first-class object. То, что его результат является функцией — понятно. Например, можно было бы exceptionProtect в Array.map передать или куда-нибудь еще.


Ну такое возможно если Array.map тоже шаблон, и в том же D есть такая штука как Template Alias Parameters которая облегчает такое использование.

M>Другой "шаблон" построить в рантайме и т.п.


А вот это вряд-ли когда-нибудь будет в языках типа C++/D. Мне кажется полноценно это реализуемо только в динамически типизированных языках.

M>И вот как раз полноценной работы с типами мне хватило бы. Причем передачи AST мне ни в один шаблон не нужно. Туда передаются значения разной природы. Это могут быть объекты, это могут быть функции и на выходе как-то строится тип результата. Т.е. "более типизированная" "динамика". В принципе, возможность работы таких "шаблонов" в рантайме упирается в необходимость хорошего RTTI, возможность порождать описания типов в рантайме и "динамический" способ вызова функции.


Есть подозрения что в результате получится разновидность лиспа типа Dylan.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.