начал изучать F# сегодня после обеда. похоже, что к концу дня уже и закончил. никакой дополнительной гибкости по сравнению с C# не наблюдается. взять tuples. ок, я могу сматчить первый элемент как (x, _), аналогично head в списке. а как мне сматчить остаток (e.g. tail)? или как итерировать по тупелу заранее неизвестного типа? или как динамически создать тупел, имея, скажем, список типов элементов? а ведь без перечисленного мной ничего осмысленно реляционного не написать. вот у них ничего не пошевелилось в душе, когда они хуярили эти конструкторы?
Tuple(T1)
Tuple(T1, T2)
Tuple(T1, T2, T3)
Tuple(T1, T2, T3, T4)
Tuple(T1, T2, T3, T4, T5)
Tuple(T1, T2, T3, T4, T5, T6)
Tuple(T1, T2, T3, T4, T5, T6, T7)
Tuple(T1, T2, T3, T4, T5, T6, T7, T8)
bonus: Action(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)
видимо, Билл Гейтс сказал, что 16 параметров должно быть достаточно для любого метода.
Tuple(T1)
Tuple(T1, T2)
Tuple(T1, T2, T3)
Tuple(T1, T2, T3, T4)
Tuple(T1, T2, T3, T4, T5)
Tuple(T1, T2, T3, T4, T5, T6)
Tuple(T1, T2, T3, T4, T5, T6, T7)
Tuple(T1, T2, T3, T4, T5, T6, T7, T8)
bonus: Action(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)
видимо, Билл Гейтс сказал, что 16 параметров должно быть достаточно для любого метода.
(no subject)
Date: 2010-08-20 01:19 am (UTC)Вроде паттерны типа first::second::_ (сосиска может быть произвольной длины) должны работать.
По поводу енумирирования по произвольной tuple - это тебе, наверно, захотелось compile-time вычислений ("метапрограммирования" в стиле C++-темплейтов?), такого в F# нет.
(no subject)
Date: 2010-08-20 05:47 am (UTC)Это для списков, не для туплов.
109 хочет использовать туплы как гетерогенные списки, а это без выкрутасов не типизируется. Есть ли в F# достаточные выкрутасы - не в курсе.
(no subject)
Date: 2010-08-20 06:45 am (UTC)"Динамически создать tuple, имя список типов" - во первых, не tuple а его тип, во вторых, это уже метапрограммирование или программирование на типах, кому что нравится.
В статически типизированных языках, действительно, часто не хватает таких возможностей и кажется, что они бы были серебряной пулей. Но это все до первой попытки реализовать их самостоятельно - в итоге оказывается, что получается что-то похоже или на Template Haskell с его адским вуду, или на Common Lisp с скобочками и макросами. Это если встраивать метапрограммирование в язык таким образом, чтобы его хоть как-то можно было использовать, не сломав мозг.
Альтернатива этому делу - кодогенерация, которая тоже не панацея. К широкому использованию непригодна, т.к. код кодогенератора при хоть сколько нибудь нетривиальной задаче превращается в жуткий ад.
Я сейчас как раз на F# пишу кодогенератор для model-driven design, накушался всего этого по полной программе :)
(no subject)
Date: 2010-08-20 06:46 am (UTC)(no subject)
Date: 2010-08-20 06:51 am (UTC)(no subject)
Date: 2010-08-20 07:17 am (UTC)и тип, и сам кортеж. у меня есть метаданные, например [int; string; DateTime], а теперь мне надо создать инстанс и вставить в таблицу, ну или другую коллекцию по моему усмотрению.
всё это уже делалось разными фреймворками много раз, но за отсутствием языковой поддержки всегда выходило коряво. а тут, казалось бы, наконец можно сделать хорошо, ан нет, получилось как всегда.
(no subject)
Date: 2010-08-20 07:20 am (UTC)> open System;;
> let tupleInstance = (1,"zhopej",DateTime.Now);;
val tupleInstance : int * string * DateTime =
(1, "zhopej", 20.08.2010 10:20:30)
(no subject)
Date: 2010-08-20 07:32 am (UTC)(no subject)
Date: 2010-08-20 07:33 am (UTC)ну то есть если мы говорим, что F#-ские кортежи хороши для представления датабазных кортежей, то я прошу написать мне SqlDataReader.GetValue(i)
> тебе, наверно, захотелось compile-time вычислений
нет, мне как раз в рантайме надо это делать.
(no subject)
Date: 2010-08-20 07:36 am (UTC)нет. мне нужна удобная языковая поддержка датабазных кортежей. а туплами их назовут, или хрюплами, пофиг. собственно, самим словом tuple их так позиционировали, но использовать их для этой цели, как выяснилось, невозможно.
(no subject)
Date: 2010-08-20 07:39 am (UTC)А что еще нужно, все остальное из этого комбинируется.
(no subject)
Date: 2010-08-20 07:47 am (UTC)Собственно говоря, нет проблемы сделать это через Reflection, но это же натягивание совы на глобус и добровольный отказ от преимуществ статической типизации.
SqlDataReader.GetValue(i) и прочий ADO.NET, JDBC, итд - это динамическая типизация.
Чтобы одновременно было и это и статическая типизация - нужна очень хитрая система типов, с инкрементальной типизацией. Она все равно валится будет в рунтайме, если будут ошибки типов, т.е. гарантии валидности будут более слабые, но в отличие от теперешней чисто динамической типизации - валится будет раньше, на этапе prepare запроса (или еще раньше, при подключении к БД), а не на этапе выполнения с обращением к кривому типу и то если результат запроса не пустой.
(no subject)
Date: 2010-08-20 07:47 am (UTC)и GetValue(i) напиши тоже заодно (см. выше), чтобы два раза не вставать.
(no subject)
Date: 2010-08-20 07:54 am (UTC)(no subject)
Date: 2010-08-20 07:59 am (UTC)(no subject)
Date: 2010-08-20 08:00 am (UTC)Type list - это то же самое, закат солнца вручную - реализация динамической типизации руками поверх языка со статической типизацией.
Во всех попадавшихся мне под руку языках интеграция этого в статическую типизацию или невозможна, или реализуется через метапрограммирование на макросах, или через инфернальный type-level programming типа того же HList. А i там приходится выражать в нумералах чёрча, ага.
Еще один вариант - Reflection
И кстати, насчет GetValue(i) - предлагаю сразу задуматься, какие применения для него? Я пока вижу только как адаптер к нетипизированным вещам вроде DataGrid или типа "вывести тупл целиком в строку".
(no subject)
Date: 2010-08-20 08:09 am (UTC)Дельфи(TDataset, bde и dbexpress и прочая), ADO, ADO.NET, и 90% других базоданновых либ - это все динамическая типизация.
F# tuples, C# class и struct, записи, ADT и прочее - это статическая типизация, со своей достаточно строгой теорией. Tuples в F# введены, т.к. это очевидный элемент оной теории.
Интеграция этого дела возможна, но тянет за собой множество заморочек, которые отражаются в крайней невменяемости большинства ORM-либ. Оные ORM как раз и решают задачу "адаптировать систему типов БД и систему типов языка". Прозрачной интеграции я пока не видел вообще нигде и ни разу, т.к. языки у которых есть нужные для этого фичи, либо сами по себе динамически типизированы, либо в продакшене не используются/
Я лично tuple использую массово чтобы не создавать руками новые типы данных, если мне нужно вернуть два-три значения в результате функции. Если больше - то лучше использовать записи, то бишь те же самые туплы, но вместо порядка полей в них поля именованные.
(no subject)
Date: 2010-08-20 08:19 am (UTC)эээ... вообще-то через него, или его аналог, работает вообще всё что database-related, включая "типизированные" датасеты, таблицы, whatever.
в свою очередь, предлагаю задуматься над причиной появления инфернального HList. значит, есть таки потребность? ну и заодно, что лучше, иметь tuples, которые не tuples, и сбоку прикрученные классы, которые на самом деле позволяют с данными работать, или реализовать один раз нормально?
я не вижу, почему так принципиально трудно сделать нормальную языковую поддержку для операции, например, [int; string] -> int * string - при том что, как ты сам правильно заметил, сделать это через reflection не представляет проблем (unless число элементов в списке типов больше восьми ;).
всё, я пошел спать, глаза слипаются.
(no subject)
Date: 2010-08-20 08:36 am (UTC)Теоретически трудно сделать, да. Т.к это означает все те же compile-time вычисления.
(no subject)
Date: 2010-08-20 08:48 am (UTC)(no subject)
Date: 2010-08-20 08:53 am (UTC)* спрашивать у юзера коннект к БД, таблицу, логиниться
* показать список полей
* показать первых 30 строк таблицы.
Юзер может ввести БД и таблицу, какие угодно (созданные после компиляции программы).
Ява, Бейсик, паскакаль, писон -- без проблем. Ф#?
(no subject)
Date: 2010-08-20 09:04 am (UTC)Статическая система типов F# в данном случае не поможет ничем и никак.
Хотя у меня есть идея реализовать именно для этого use case собственный фреймворк с инкрементальной типизацией и кодогенерацией-компиляцией в рунтайме. Пока отложено в долгий ящик, т.к. решение задачи требует сначала реализовать то же самое в более простом варианте, с предварительной кодогенерацией.
Ну и единственное место в продакшене где у меня динамическая и статическая типизации пересекаются - это когда из такого грида нужно отобразить написанный руками конкретно под данную таблицу редактор или выполнить какой-нибудь расчет, тоже исходя из данных таблицы. Приходится заниматься приведениями типов, обращениями по имени к полям, итд :)
(no subject)
Date: 2010-08-20 09:33 am (UTC)вы хотите функцию, (T1, T2)->int -> ??? : f, такую что f(a,b)(1) = T1:a, f(a,b)(2) = T2:b
подозреваю что проверить при компиляции отсутствие ошибок типизации в выражении, содержащем такую функцию, нельзя, поэтому есть две отдельных функции (T1,T2)->T1: f(1) и (T1,T2)->T2: f(2), .Item1 и .Item2 соответвенно.
поскольку в момент компиляции метаданные отношения, для которого нужно создавать кортежи, вам не известны, то в любом случае с туплами или без них, придется динамически по описанию тупла генерить его тип и потом сами туплы.
(no subject)
Date: 2010-08-20 09:35 am (UTC)Список имеет тип List A = A * List A | EmptyList.
Список это элемент типа A и ещё точно также список, либо пустой список.
Другими словами, списки гомогенны (содержат элементы одинакового типа данных).
Если же у нас списки гетерогенные - начинается веселуха.
В терминах ООП у нас вводится базовый класс Base и два наследника - A и B
И мы получается список Base'ов... А не список A, B.
В терминах ФЯП это описывается как:
Base = A | B
List Base = Base * List Base | EmptyList;
Теперь приходим к понимаю, что для списка длиной два есть четыре варианта:
A, A
A, B
B, A
B, B
Ну и как это говно типизировать?
Вот и появлются tuple.
Tuple 'a 'b = a' * 'b;
get (a,b) i = match i with
0 -> a
1 -> b
end;
Какой тип результата get?
Естественно, a | b
Теперь проблема понятна?
(no subject)
Date: 2010-08-20 09:39 am (UTC)1) функция, превращающая несколько значений в значение декартового произведения типов
2) функция проекции этого произведения обратно в компоненты
что и написано в документации по приведенной вами ссылке
собственно, самим словом tuple их так позиционировали.