F#

Aug. 19th, 2010 05:00 pm
109: (Default)
[personal profile] 109
начал изучать 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 параметров должно быть достаточно для любого метода.

(no subject)

Date: 2010-08-20 07:17 am (UTC)
From: [identity profile] 109.livejournal.com
> "Динамически создать tuple, имея список типов" - во первых, не tuple а его тип

и тип, и сам кортеж. у меня есть метаданные, например [int; string; DateTime], а теперь мне надо создать инстанс и вставить в таблицу, ну или другую коллекцию по моему усмотрению.

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

(no subject)

Date: 2010-08-20 07:20 am (UTC)
From: [identity profile] metaclass.livejournal.com
вот, языковая поддержка:
> 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:47 am (UTC)
From: [identity profile] 109.livejournal.com
я уверен, что ты понимаешь, что я имею в виду, только прикидываешься. у меня нет никаких "zhopej", когда я код пишу. да и у тебя нет. а есть row metadata в виде, например, Type list.

и GetValue(i) напиши тоже заодно (см. выше), чтобы два раза не вставать.

(no subject)

Date: 2010-08-20 08:00 am (UTC)
From: [identity profile] metaclass.livejournal.com
про GetValue я уже написал там
Type list - это то же самое, закат солнца вручную - реализация динамической типизации руками поверх языка со статической типизацией.
Во всех попадавшихся мне под руку языках интеграция этого в статическую типизацию или невозможна, или реализуется через метапрограммирование на макросах, или через инфернальный type-level programming типа того же HList. А i там приходится выражать в нумералах чёрча, ага.
Еще один вариант - Reflection

И кстати, насчет GetValue(i) - предлагаю сразу задуматься, какие применения для него? Я пока вижу только как адаптер к нетипизированным вещам вроде DataGrid или типа "вывести тупл целиком в строку".

(no subject)

Date: 2010-08-20 08:19 am (UTC)
From: [identity profile] 109.livejournal.com
> И кстати, насчет GetValue(i) - предлагаю сразу задуматься, какие применения для него?

эээ... вообще-то через него, или его аналог, работает вообще всё что database-related, включая "типизированные" датасеты, таблицы, whatever.

в свою очередь, предлагаю задуматься над причиной появления инфернального HList. значит, есть таки потребность? ну и заодно, что лучше, иметь tuples, которые не tuples, и сбоку прикрученные классы, которые на самом деле позволяют с данными работать, или реализовать один раз нормально?

я не вижу, почему так принципиально трудно сделать нормальную языковую поддержку для операции, например, [int; string] -> int * string - при том что, как ты сам правильно заметил, сделать это через reflection не представляет проблем (unless число элементов в списке типов больше восьми ;).

всё, я пошел спать, глаза слипаются.

(no subject)

Date: 2010-08-20 08:36 am (UTC)
From: [identity profile] metaclass.livejournal.com
[typeof(int);typeof(string)] -> int*string?

Теоретически трудно сделать, да. Т.к это означает все те же compile-time вычисления.

(no subject)

Date: 2010-08-20 09:49 am (UTC)
From: [identity profile] zamotivator.livejournal.com
Рискну выказать предположение.
GetValue(i) нужен для одной единственной цели - построить итерацию по таплу для обработки.
По идее, тут достаточно показать человеку как использовать параметрические функции а также map/etc, и проблема уйдёт.

Это в дополнении к:
http://109.livejournal.com/539588.html?thread=2049476#t2049476

(no subject)

Date: 2010-08-20 10:12 am (UTC)
From: [identity profile] metaclass.livejournal.com
map тут не поможет же, мы ж итерируемся не по списку (данным), а по структуре(метаданным).
Тут помогло бы что-то вроде автоматической генерации подобной функции для любого типа тайпла. Т.е. все тайплы реализуют какой-нибудь интерфейс(typeclass в терминах хаскеля) с методами GetFieldCount GetFieldName(i), GetValue(i) и прочая.

(no subject)

Date: 2010-08-20 10:48 am (UTC)
From: [identity profile] zamotivator.livejournal.com
Ну если у нас гетерогенный контейнер - список сумма - то why not?

(no subject)

From: [identity profile] metaclass.livejournal.com - Date: 2010-08-20 11:00 am (UTC) - Expand

(no subject)

From: [identity profile] 109.livejournal.com - Date: 2010-08-21 02:12 am (UTC) - Expand

(no subject)

From: [identity profile] metaclass.livejournal.com - Date: 2010-08-21 06:19 am (UTC) - Expand

(no subject)

Date: 2010-08-21 02:09 am (UTC)
From: [identity profile] 109.livejournal.com
ну вот да, что-то типа этого. ну и хотелось бы языковую поддержку хотя бы для операций [type1; type2; ...] -> (type1 * type2 * ...) и GetValue(i)

а, ну и ещё - возможно, что это и так есть, просто я не знаю - хотелось бы иметь человеческое инстанцирование из type variable, типа:

class My1 {}
class My2 {}
Type t;
t = My1;
My1 my1 = t.New();// инстанцируем My1
t = My2;
My2 my2 = t.New();// инстанцируем My2

в дельфи было что-то близкое, но я забыл уже. понятно, что через Reflection в дотнете это можно, хочется straightforward syntax.

(no subject)

From: [identity profile] metaclass.livejournal.com - Date: 2010-08-21 06:18 am (UTC) - Expand

(no subject)

Date: 2010-08-21 01:52 am (UTC)
From: [identity profile] 109.livejournal.com
ну так покажите же уже наконец человеку, как итерировать по таплу, а то пока все пишут, что это невозможно.

параметрические функции - это функции с параметрами, да? (что такое параметрические функции в математике я знаю, а что вы тут имели в виду - нет)

(no subject)

From: [identity profile] zamotivator.livejournal.com - Date: 2010-08-21 07:11 am (UTC) - Expand

(no subject)

From: [identity profile] metaclass.livejournal.com - Date: 2010-08-21 07:40 am (UTC) - Expand

(no subject)

From: [identity profile] zamotivator.livejournal.com - Date: 2010-08-21 08:01 am (UTC) - Expand

(no subject)

Date: 2010-08-20 11:29 pm (UTC)
From: [identity profile] 109.livejournal.com
нет, не означает. генерики в донете, если вам неизвестно, инстанцируются в рантайме, в отличие от плюсов, например.

(no subject)

Date: 2010-08-21 06:09 am (UTC)
From: [identity profile] metaclass.livejournal.com
То, что они инстанцируются в рантайме, совершенно не отменяет того факта, что информация о их структуре используется при компиляции для статической проверки и вывода типов.

(no subject)

Date: 2010-08-20 09:35 am (UTC)
From: [identity profile] zamotivator.livejournal.com
я не вижу, почему так принципиально трудно сделать нормальную языковую поддержку для операции, например, [int; string] -> int * string - при том что, как ты сам правильно заметил, сделать это через reflection не представляет проблем (unless число элементов в списке типов больше восьми ;)..
Список имеет тип 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 10:02 am (UTC)
From: [identity profile] metaclass.livejournal.com
Так ты представь, что у тебя не два поля, а двадцать. И что типы полей могут быть любые. И получаем комбинаторный взрыв из типов функций.

(no subject)

Date: 2010-08-20 10:47 am (UTC)
From: [identity profile] zamotivator.livejournal.com
Вот именно, о чём и речь

(no subject)

Date: 2010-08-21 01:28 am (UTC)
From: [identity profile] 109.livejournal.com
> Если же у нас списки гетерогенные - начинается веселуха

в F# нет гетерогенных списков.

> Теперь проблема понятна?

она и до того была понятна - в F# нет языковой поддержки для довольно тривиальной вещи, которая мне нужна.

(no subject)

Date: 2010-08-21 06:55 am (UTC)
From: [identity profile] zamotivator.livejournal.com
она и до того была понятна - в F# нет языковой поддержки для довольно тривиальной вещи, которая мне нужна.
Её нигде нет. Кроме, разве что, Haskell

(no subject)

From: [identity profile] metaclass.livejournal.com - Date: 2010-08-21 07:06 am (UTC) - Expand

(no subject)

From: [identity profile] zamotivator.livejournal.com - Date: 2010-08-21 07:11 am (UTC) - Expand

(no subject)

Date: 2010-08-20 08:48 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Функция создания инстанса будет возвращать нечто, тип чего при компиляции неизвестен, т.к. определяется содержимым входного списка. Т.е. в рамках обычной статической типизации (а в F# она) это невозможно. Возможно в динамической (привет тонны тестов) и в зависимой (привет катаморфизмы, эндофункторы и санитары).

(no subject)

Date: 2010-08-20 10:04 am (UTC)
From: [identity profile] metaclass.livejournal.com
Не, катаморфизмы и эндофункторы у нас и так есть, это не проблема :)
А вот санитары да, начинаются вместе с dependent types.

(no subject)

Date: 2010-08-21 01:56 am (UTC)
From: [identity profile] 109.livejournal.com
> Не, катаморфизмы и эндофункторы у нас и так есть, это не проблема :)

hey, hey, держите себя в руках! :)

тут не семинар по теории категорий, а как бы код попроще да поперформантней написать.

(no subject)

Date: 2010-08-21 01:23 am (UTC)
From: [identity profile] 109.livejournal.com
> Функция создания инстанса будет возвращать нечто, тип чего при компиляции неизвестен, т.к. определяется содержимым входного списка. Т.е. в рамках обычной статической типизации (а в F# она) это невозможно.

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

MyBaseType FactoryMethod(int type)
{
if (type == 1) return new MyType1();
if (type == 2) return new MyType2();
}

(no subject)

Date: 2010-08-21 06:13 am (UTC)
From: [identity profile] metaclass.livejournal.com
Тип известен, кстати, вернее констрейнт типа - "только типы унаследованные или равные MyBaseType".
То, что фабрика может вернуть любой из унаследованных типов - для этого в F# даже специальный синтаксис имеется: #тип

(no subject)

Date: 2010-08-22 10:39 pm (UTC)
From: [identity profile] 109.livejournal.com
ну, и? я тут только и делаю, что конкретными примерами демонстрирую невалидность аргументов за то, что нельзя было сделать по-человечески. а мне отвечают: "а, ну так это называется [bla]". мало того, что я и так знаю, как это называется, аргументам-то это никак не помогает.

(no subject)

Date: 2010-08-21 08:12 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Известен - MyBaseType.

Так-то можно, но придется либо объединять возможные типы значений в один ADT
http://109.livejournal.com/539588.html?thread=2063556&format=light#t2063556
либо возвращать общий предок string и int - object, но кому это надо?

Profile

109: (Default)
109

March 2019

S M T W T F S
     12
3456789
101112131415 16
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags