Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.192] |
|
|
Правила раздела:
| Страницы: (495) « Первая ... 424 425 [426] 427 428 ... 494 495 ( Перейти к последнему сообщению ) |
Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
|
Сообщ.
#6376
,
|
|
|
|
Гля, вы гениальны! А я и не догадывался! (если кто не понял - это вариация на тему "спасибо, кэп"). Давайте серьёзно, а? А то второй раз меня забанят... Вы же прекрасно поняли, что длина подобного списка вводится пользователем. |
|
Сообщ.
#6377
,
|
|
|
|
Цитата korvin @ Да пожалуйста: ![]() ![]() xs = Cons 1 $ Cons 2 $ Cons 3 Nil ys = Cons 1 $ Cons 2 Nil списки построены независимо, при этом имеют разные типы, поэтому не пройдут в (scalarProduct xs ys) еще на этапе компиляции Так это статически построенные списки. Цитата Почему? Попробуй абстрагироваться от способа создания списков. Суть в том, что сигнатура функции test' (и scalarProduct) не позволит применить ее к двум спискам разной длины, на этапе компиляции. Это функции занимаются и конструированием списка, и вычислением итогового результата. Это совершенно бессмысленно в реальных условиях. |
|
Сообщ.
#6378
,
|
|
|
|
Цитата D_KEY @ Это функции занимаются и конструированием списка, и вычислением итогового результата. Это совершенно бессмысленно в реальных условиях. scalarProduct не занимается конструированием списка так-то, а test' не занимается вычислением результата. Вот еще со статическим map ![]() ![]() import System data Nil = Nil data Cons a = Cons Integer a class List a where lmap :: (Integer -> Integer) -> a -> a instance List Nil where lmap _ Nil = Nil instance List a => List (Cons a) where lmap f (Cons n a) = Cons (f n) $ lmap f a class List a => ScalarProduct a where scalarProduct :: a -> a -> Integer instance ScalarProduct Nil where scalarProduct Nil Nil = 0 instance ScalarProduct a => ScalarProduct (Cons a) where scalarProduct (Cons n1 a1) (Cons n2 a2) = n1 * n2 + scalarProduct a1 a2 fx i = 2*i + 1 fy i = i^2 test :: Integer -> Integer test n = test' n 0 Nil Nil where test' :: ScalarProduct a => Integer -> Integer -> a -> a -> Integer test' 0 _ xs ys = scalarProduct (lmap fx xs) (lmap fy ys) test' n i xs ys = test' (n-1) (i+1) (Cons i xs) (Cons i ys) main :: IO () main = print . test . read . head =<< getArgs Вот, кстати, сегодня еще наткнулся на любопытный пост: Цитата вот на счет контрактов часто жалуются. а что толку от контрактов, если они не проверяются на практике. дак вот, встретил на рсдн хороший пост: http://rsdn.ru/forum/decl/4522924.flat.aspx там правда примеры сложноватые для нехаскелистов, поэтому как будет время(на днях), напишу пару игрушечных примера. что бы без разных монадныых трансформеров суть топика такова. параметризируем монаду двумя типами: пост- и пред- условиями. что получаем на практике - проверку контракта в момент компиляции. пример(игрушечную модель которого я напишу сегодня или завтра): есть у нас файл. в него можно писать, только если он открыт для записи. закрывать только если он открыт. и если он закрыт, то писать в него нельзя. что нам предлагают современные языки(а вернее их библиотеки). если мы попытаемся писать в закрытый файл, то получим исключение в рантайме. но параметризированные монады позволяют отловить данную ошибку - в момент компиляции. |
|
Сообщ.
#6379
,
|
|
|
|
А я вот всё ещё не понял. Так списки совсем динамические, или динамически просто заполняются?
|
|
Сообщ.
#6380
,
|
|
|
|
Цитата korvin @ Вот, кстати, сегодня еще наткнулся на любопытный пост: А мона ссылку на оригинальный пост ?? |
|
Сообщ.
#6381
,
|
|
|
|
Цитата jack128 @ А мона ссылку на оригинальный пост ?? Re: Выгоды контрактного программирования (design by contract) квадратосрач2 + Добавлено Цитата Повстанець @ А я вот всё ещё не понял. Так списки совсем динамические, или динамически просто заполняются? Что значит "совсем динамические"? Это как списки в CL например? |
|
Сообщ.
#6382
,
|
|
|
|
тупо в лоб..
![]() ![]() type TFirst = array[0..5] of Integer; TSecond = array[0..6] of Integer; var SP : Integer; i : Integer; First : TFirst; Second : TSecond; begin {$IF LENGTH(First) <> LENGTH(Second)} {$MESSAGE ERROR 'Ошибка!'} {$IFEND} First[0] := 0; First[1] := 1; First[2] := 2; First[3] := 3; First[4] := 4; Second[0] := 0; Second[1] := 1; Second[2] := 2; Second[3] := 3; Second[4] := 4; SP := 0; for i := Low(First) to High(First) do SP := SP + First[i] * Second[i]; Writeln(SP); Readln; end. P.S. всё это очень похоже на плюсовые ассерты времени компиляции (или как их там?).. Добавлено Цитата korvin @ но параметризированные монады позволяют отловить данную ошибку - в момент компиляции. Ну а если файл будет открываться/закрываться в виртуальном методе? P.S. согласен с D_KEY, подходит не для всех случаев (а для большинства тех, что подходит, польза сугубо академическая). |
|
Сообщ.
#6383
,
|
|
|
|
Цитата MyNameIsIgor @ Гля, вы гениальны! А я и не догадывался! (если кто не понял - это вариация на тему "спасибо, кэп"). Тогда в чем вопрос? Цитата MyNameIsIgor @ Давайте серьёзно, а? А то второй раз меня забанят... Так будь серьёзен, тогда не забанят. Цитата MyNameIsIgor @ Вы же прекрасно поняли, что длина подобного списка вводится пользователем. Какого "подобного"? Я предоставил два несимметричных списка. Если тебе нужны списка, полученных из разных значений m и n, введенных пользователем, то естественно компилятор не может гарантировать, что они будут равны. И никакой компилятор никакого языка никогда не сможет этого сделать. Максимум, что он может -- потребовать проверку в сомнительных случаях и уже после проверки считать, что равенство/неравенство длин доказано. (Хаскельный) компилятор в общем случае не может даже доказать, что результаты f и g будут иметь одинаковый тип в следующем коде: ![]() ![]() test2 :: Integer -> Integer test2 n = scalarProduct (f n 0 Nil) (g n 0 Nil) where f :: ScalarProduct a => Integer -> Integer -> a -> a f 0 _ xs = xs f m i xs = f (m-1) (i+1) (Cons (2*i+1) xs) g :: ScalarProduct a => Integer -> Integer -> a -> a g 0 _ xs = xs g m i xs = f (m-1) (i+1) (Cons (i^2) xs) потому что (в Хаскелле) типы нельзя параметризовать рантайм-переменными, т.е. он не знает, что типы результатов f и g зависят только от m и при одинаковых m (а в данном случае они одинаковы, т.к. в них передается значение одной и той же переменной n) будут одинаковы, т.е. списки будут иметь равные длины. Добавлено Цитата DesweR @ Ну а если файл будет открываться/закрываться в виртуальном методе? О каких виртуальных методах в Хаскеле идет речь? И вообще о чем, я что-то не понял. Цитата DesweR @ согласен с D_KEY, подходит не для всех случаев (а для большинства тех, что подходит, польза сугубо академическая). Ты просто тоже не понял, о чем пример. Еще раз для всех: основной смысл примера не в том, чтобы знать какая длина у списка на этапе компиляции, это в общем случае невозможно, а в том, чтобы гарантировать для функции, обрабатывающей два списка (в примере -- scalarProduct), что она не получит два списка разной длины и гарантировать это на этапе компиляции. Добавлено Цитата DesweR @ тупо в лоб.. ![]() ![]() type TFirst = array[0..5] of Integer; TSecond = array[0..6] of Integer; ... А теперь то же самое, только чтоб длина задавалась в рантайме, ок? |
|
Сообщ.
#6384
,
|
|
|
|
Цитата korvin @ О каких виртуальных методах в Хаскеле идет речь? И вообще о чем, я что-то не понял. Это мы не поняли, тут речь о C++/C#/Java/Delphi Цитата korvin @ А теперь то же самое, только чтоб длина задавалась в рантайме, ок? Не |
|
Сообщ.
#6385
,
|
|
|
|
Цитата korvin @ А теперь то же самое, только чтоб длина задавалась в рантайме, ок? Эмм, а где в коде на Хаскелле задание длины списка в рантайме? |
|
Сообщ.
#6386
,
|
|
|
|
Т.е. смотрите:
![]() ![]() test' :: ScalarProduct a => Integer -> Integer -> a -> a -> Integer test' 0 _ xs ys = scalarProduct xs ys a == a, т.е. типы xs и ys будут гарантировано одинаковы, именно это и разрешает применение scalarProduct к ним (она тоже требует одинаковые типы), а, поскольку, собственно функция вычисляется в рантайме, то и длина может быть задана в рантайме. Да, судя по всему в этом случае тип a неизвестен на этапе компиляции, поэтому он будет строиться в динамике, как и диспетчеризация scalarProduct (выбор реализации между типами Cons и Nil) будет соответственно происходить в рантайме, хотя раньше я думал, что диспетчеризация тайпклассовых функций происходит только в компайл-тайме. Добавлено Цитата Мяут-Настоящий @ Эмм, а где в коде на Хаскелле задание длины списка в рантайме? ![]() ![]() ![]() ... test :: Integer -> Integer test n = test' n 0 Nil Nil where test' :: ScalarProduct a => Integer -> Integer -> a -> a -> Integer test' 0 _ xs ys = scalarProduct (lmap fx xs) (lmap fy ys) test' n i xs ys = test' (n-1) (i+1) (Cons i xs) (Cons i ys) main :: IO () main = print . test . read . head =<< getArgs Длина берется из первого аргумента, переданного программе: ![]() ![]() D:\usr\Development\haskell> ghc -o test test.hs [1 of 1] Compiling Main ( test.hs, test.o ) Linking test.exe ... D:\usr\Development\haskell> test 1 0 D:\usr\Development\haskell> test 4 86 D:\usr\Development\haskell> test 15 23065 D:\usr\Development\haskell> Добавлено Цитата DesweR @ Это мы не поняли, тут речь о C++/C#/Java/Delphi ![]() Поэтому я ту цитату поместил в спойлер, чтобы не мозолила глаза, а кого-нибудь оно могло и заинтересовать. |
|
Сообщ.
#6387
,
|
|
|
|
Цитата korvin @ И никакой компилятор никакого языка никогда не сможет этого сделать. О том и речь. Что не может. А от приведенных примеров толку немного. Но если смотреть на задачу, как на теоретическую, то да, в С++ для формирования таких списков в рантайме придется отказаться на определенном этапе от рекурсивного шаблонного типа(как собственно и происходит с дженериками на автомате), потому код будет не столь наглядным. Цитата Максимум, что он может -- потребовать проверку в сомнительных случаях и уже после проверки считать, что равенство/неравенство длин доказано. Разве он это будет делать посредством типизации? Цитата Это было понятно(см. выше я где-то это же самое говорил кому-то).Ты просто тоже не понял, о чем пример. Еще раз для всех: основной смысл примера не в том, чтобы знать какая длина у списка на этапе компиляции, это в общем случае невозможно, а в том, чтобы гарантировать для функции, обрабатывающей два списка (в примере -- scalarProduct), что она не получит два списка разной длины и гарантировать это на этапе компиляции. Но профит тут исключительно теоретический. На практике гораздо надежнее/проще/полезнее будет как-нибудь так: ![]() ![]() int n; std::cin >> n; std::vector<int> v1(n), v2(n); И даже ошибиться в таком коде гораздо сложнее Добавлено Цитата Мяут-Настоящий @ Цитата korvin @ А теперь то же самое, только чтоб длина задавалась в рантайме, ок? Эмм, а где в коде на Хаскелле задание длины списка в рантайме? ![]() Ну как же, функция main' же в том коде принимает n. На самом деле просто превосходный пример, демонстрирующий разницу между шаблонами и полиморфными типами/дженериками. |
|
Сообщ.
#6388
,
|
|
|
|
Цитата D_KEY @ Разве он это будет делать посредством типизации? С их помощью. |
|
Сообщ.
#6389
,
|
|
|
|
Цитата korvin @ Да, судя по всему в этом случае тип a неизвестен на этапе компиляции, поэтому он будет строиться в динамике, как и диспетчеризация scalarProduct (выбор реализации между типами Cons и Nil) будет соответственно происходить в рантайме, хотя раньше я думал, что диспетчеризация тайпклассовых функций происходит только в компайл-тайме. Нет, не будет тип строиться на этапе выполнения. Это не требуется. Компилятор итак знает, что типы будут корректны - ему достаточно рассмотреть "текущую" итерацию, если в ней типы корректны, значит будут корректны и в следующей. Добавлено Собственно, С++ шаблоны напрямую не работают как раз потому, что они не являются (полиморфными) типами - они именно шаблоны, по которым генерируются конкретные не параметризованные типы. |
|
Сообщ.
#6390
,
|
|
|
|
Цитата D_KEY @ Это было понятно(см. выше я где-то это же самое говорил кому-то). Но профит тут исключительно теоретический. Это все равно, что заявлять, что от статической типизации профит исключительно теоретический. Или, что от вывода типов профит исключительно теоретический. Или от шаблонов/дженериков. Или от контрактов. Цитата D_KEY @ На практике гораздо надежнее/проще/полезнее будет как-нибудь так: ![]() ![]() int n; std::cin >> n; std::vector<int> v1(n), v2(n); И даже ошибиться в таком коде гораздо сложнее ![]() В каком месте тут надежней/проще/полезней и даже ошибиться гораздо сложнее? И собственно, чем это отличается от хаскеллного кода? Как теперь будет выглядеть функция scalarProduct для vector<int>? Добавлено Цитата D_KEY @ Нет, не будет тип строиться на этапе выполнения. Это не требуется. Компилятор итак знает, что типы будут корректны - ему достаточно рассмотреть "текущую" итерацию, если в ней типы корректны, значит будут корректны и в следующей. Будет. Потому что инстансы тайпклассов диспетчеризуются по типам, для того, чтобы на каждой "итерации" правильно выбирать реализацию scalarProduct, тип списка должен построиться полностью. Для тайпчека это не требуется, да. |