LINUX.ORG.RU

Ответ на: комментарий от quasimoto

А нужно.

Как раз не нужно. В типе должна быть семантика, а не мусор.

Ничего не упало.

ф-я вернула nothing = вернула ошибочный код возврата = бросила исключение. Ну называть это упала или нет - выбор каждого уже.

Только в последнем случае можно променять Either на исключение

Так больше нигде и не надо. Будет просто «Config -> ..., BackendConnection -> ..., LocalCache RemoteCache -> ..., это же самое внутри структур в data, ... -> (Int Double), ... -> ParserResult ParserError». Без мусорных Either/Maybe.

ни где-то ещё — return codes и exceptions это две разные вещи

Ну да, return codes - устарелое неюзабельное говно, а исключения - система специально разработанная ему на замену.

другое — может работать нелокально через весь стек вызовов разных функций.

Семантика-то одна в итоге.

anonymous
()
Ответ на: комментарий от dmfd

А как отличать чистую функцию от нечистой?

А в документацию посмотреть. Если она грязная - там будет написано.

anonymous
()
Ответ на: комментарий от dmfd

Чертовски удобно придумано. А типы, я полагаю, тоже нужно в документации смотреть?

Какие типы?

anonymous
()
Ответ на: комментарий от anonymous

Типы данных. Или вы не тот анонимус, который утверждал, что статика ущемляет его права писать некорректный код?

dmfd
()
Ответ на: комментарий от dmfd

Смотри, если ты применяешь функцию - значит ты знаешь, что она делает (то есть уже посмотрел документацию). А если ты знаешь, что она делает, то знаешь, чистая она или нет.

anonymous
()
Ответ на: комментарий от dmfd

Типы данных.

Не понял, зачем тебе типы? Надо знать как функция работает, а не на типы дрочить.

anonymous
()
Ответ на: комментарий от anonymous

Вот я и говорю, что по этой логике и типы не нужно указывать: человек умнее глупой машины, он читал документацию.

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

dmfd
()
Ответ на: комментарий от dmfd

Вот я и говорю, что по этой логике и типы не нужно указывать

Правильно, не нужно.

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

Ну если ему вдруг в рамках данной задачи так уж необходимо знать о чистоте - давай укажем соответствующей аннотацией.

anonymous
()
Ответ на: комментарий от dmfd

Там вообще то речь шла именно о том, как _человеку_ отличать. Про компилятор - это уже ты придумал. Так что ИРЛ аннотации не нужны, чистая функция или нет - известно заведомо. Что до оптимизаций - тут уже правила совершенно другие и разговор совершенно другой. В 99.9% задач оно не нужно.

anonymous
()
Ответ на: комментарий от qnikst

Что-то я не понял — чистый код вычисляется (пусть параллельно и нестрого) в какой-то _|_ (там где-то undefined, error, throw и т.п. — всё исключения), либо сложная структура содержит такой код — почему нельзя в чистом коде сделать let result = something in if isEvaluatesToBottom result then somethingElse else result с чистым же значением (result который _точно_ не какой-то _|_, либо somethingElse, ясно, что isEvaluatesToBottom не может просто протащить санк нестрогого вычисления — он должен сказать точно _|_ это или нет (и не содержит ли строгая структура его, поэтому я там поставил !, !! и NFData), но ссылочной прозрачности эта возможность не отменяет)? Мне, вообщем-то, всё равно как оно может быть реализовано, но, да, это явно более специального вида исключения нежели исключения в IO у GHC (без маскировок, асинхронности и т.п.).

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от anonymous

В типе должна быть семантика, а не мусор.

Вот в типе и есть сумма типов когда она нужна (Maybe, Either, любой вариантный ADT).

ф-я вернула nothing = вернула ошибочный код возврата = бросила исключение

* (assoc :a '((:a 1)))

(:A 1)
* (assoc :b '((:a 1)))

NIL

и в хаскеле тоже lookup из разных контейнеров и окружения (POSIX, в смысле) возвращает Maybe.

Насчёт

Семантика-то одна в итоге.

Это как-то глупо — разве что в очень далёком и абстрактном итоге, обычно семантика исключений требует дополнительного к базовой семантике (функции, возвращаемые значения) построения (как в TAPL, 14).

Так больше нигде и не надо

Ээ, я хочу передать Nothing либо Just backendConnection — в одном случае будет одна работа, в другом — другая. Аналогично с передачей Left localCache и Right remoteCache — совсем разный код по двум ветвям. Типо DI == передача через аргумент.

LocalCache RemoteCache

(Int Double)

Что это?

Ну да, return codes - устарелое неюзабельное говно

Передавать и возвращать вариантные ADT не нужно, вообще ничего передавать и возвращать не нужно — всё можно протащить через исключения, hands down!1

quasimoto ★★★★
()
Ответ на: комментарий от monk

Ты же говоришь, что «некорректная программа в языке со статической типизацией не скомпилируется». Однако компилируется, падает, предупреждений при компиляции не даёт.

Речь, наверно, про некорректные с точки зрения несовпадения типов программы. То о чём ты говоришь не имеет отношения к вопросу «статическая vs динамическая типизация» — это вопрос о тотальных и частичных (предполагающих исключительные ситуации) функциях. В хаскеле такие же частичные функции как и во всех остальных распространённых ЯП и исключения ловятся так же с помощью try/catch как и в остальных языках с исключениями. То что статическая система типов избавит от всех некорректностей вообще никто не говорит.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

ага, ещё есть проблема с тем, что _|_ есть только у boxed values, в то время, как для оптимизаций всё что можно желательно сделать unboxed, и большая часть будет сделано компилятором, а подобный подход отменит такую возможность, плюс не будет содержать плюсов по сравнению с pattern-matching-ом по ADT и их монадическому интерфейсу, если он есть..

qnikst ★★★★★
()
Ответ на: комментарий от anonymous

как _человеку_ отличать

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

и разговор совершенно другой

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

В 99.9% задач оно не нужно.

Что не в 146%-то?

dmfd
()
Ответ на: комментарий от quasimoto

некорректные с точки зрения несовпадения типов программы

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

Уж лучше Typed Racket, где что можно проверится на этапе компиляции, а всё остальное при первом же тестовом прогоне.

К слову, в нём нормально проверяется:

(define (test)
  (let ([s (read)])
    (+ s 1)))

Type Checker: Expected Number, but got Any in: s

monk ★★★★★
()
Ответ на: комментарий от qnikst

поправил, можешь не благодарить.

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

+ : (Number * -> Number) ...

Возвращает сумму произвольного количества переданных параметров типа Number

monk ★★★★★
()
Ответ на: комментарий от monk

ни типов объединений

Это вы про ADT?

и функций с бесконечным числом однотипных аргументов

Посмотрите реализацию printf на Haskell.

dmfd
()
Ответ на: комментарий от qnikst

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

qnikst ★★★★★
()
Ответ на: комментарий от monk

как работать со списками элементов произвольных типов

Экзистенциальные типы.

Или даже такой примитив

Я составлю список и воспользуюсь функцией sum.

dmfd
()
Ответ на: комментарий от dmfd

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

Ага, особенно в ленивом языке с непредсказуемыми санками. Да ты оптимист!

dave ★★★★★
()
Ответ на: комментарий от monk

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

извини, я тебя непонимаю... полную задачу давай, я не собираюсь гадать, что тебе нужно.

+ : (Number * -> Number) ...

а). ты можешь передать список, нельзя? почему?

б).

> {-# LANGUAGE TypeFamilies #-}
>
> class Add r where
>   add' :: (Integer -> Integer) -> r
> 
> instance Add Integer where
>   add' k = k 0
> 
> instance (n ~ Integer, Add r) => Add (n -> r) where
>   add' k m = add' (\n -> k (m+n))
> 
> add :: (Add r) => r
> add = add' id
>

*Main> :e
Ok, modules loaded: Main.
*Main> add 1 2 3 :: Integer
6

с тебя решение на лиспе пожалуйста.

в). можно и проще если честно, но мне лень

qnikst ★★★★★
()
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от dmfd

Экзистенциальные типы.

а вот фиг без задачи поймешь, что он там хочет, может экзистенциальные, может хватит и typeable, может dynamic хочет, а может тегирование типов, может хватит врапа в ADT, может ему SumTypes на TypeOperators нужно, а может Typed protocol, когда тип разбираемого выражения или ответа основывается на полученном типе. Все нужно и полезно для своих задач..

qnikst ★★★★★
()
Ответ на: комментарий от qnikst
(: sum (Number * -> Number))
(define (sum . xs)
  (if (null? xs)
      0
      (+ (car xs) (apply sum (cdr xs)))))

и мне не приходится писать каждый раз Integer при вызове функции

monk ★★★★★
()
Ответ на: комментарий от monk

а мне не приходится писать бесполезные функции (кроме как на ЛОРе) и читать что такое вывод типов по контексту (чтобы не выглядеть глупо).

qnikst ★★★★★
()
Ответ на: комментарий от monk

А ещё можно сделать вот так:

(: fold-left
   (All (C A B ...)
        ((C A B ... B -> C) C (Listof A) (Listof B) ... B
         ->
         C)))
(define (fold-left f i as . bss)
  (if (or (null? as)
          (ormap null? bss))
      i
      (apply fold-left
             f
             (apply f i (car as) (map car bss))
             (cdr as)
             (map cdr bss))))

В «правильном типизированном языке» так можно?

monk ★★★★★
()
Ответ на: комментарий от monk

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

*Main> let t = add 1 2 3 4 in t 5 6 :: Integer
21

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

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

вывод типов по контексту

Который приводит к таким казусам:

http://stackoverflow.com/questions/7801407/read-from-stdin-in-haskell-using-i...

или привычке руками проставлять везде тип «на всякий случай». У тебя в твоей функции Integer 4 раза повторяется. Понадобится сделать вместо него Number или Double, будешь везде руками переписывать (или IDE с рефакторингом для Хаскеля уже сделали?).

monk ★★★★★
()
Ответ на: комментарий от qnikst

Первый аргумент функция f. Второй — Элемент i типа C Третий — список элементов типа A Четвёртый и далее — списки элементов типа B

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

Если параметров всего 3, то получится foldl из Haskell'а.

monk ★★★★★
()
Ответ на: комментарий от monk

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

Hint: почему я не прописывал тип тут.

*Main> add 1 2 3 4 + 6
16

P.S. ну и не забудь, что данная задача возникла только из желания показать твоё незнание языка, не более того, в реальной жизни таких задачь нет.

qnikst ★★★★★
()
Ответ на: комментарий от anonymous

А я что-то говорил про ленивость?

Так ты еще из под анонима пишешь?

Речь завели о том, что «Чистые функции оптимизируются и распараллеливаются очень легко.» Привожу дословно.

Ну, что же. Много ли языков, где чистота гарантируется на уровне языка? И много ли среди них языков неленивых, т.е. с энергичной моделью вычислений? По правда говоря, среди популярных языков не знаю ни одного такого. Зато немного знаком с хаскелем, который гарантирует чистоту, и который является ленивым.

Значит, предполагаю, что имелся в виду все же хаскель. Тогда вспомним, что в Real World Haskell есть целая глава, посвященная распараллеливанию. И что, у вас не создалось ощущения чего-то неправильного после ее прочтения? Сколько там надо огорода городить чтобы распараллелить! Это раз.

Во-вторых, по умолчанию много-поточный рантайм хаскеля почему-то отключен в ghc (отключен -threaded). Значит, не все там так благополучно. И это можно понять.

Может быть, дело в санках (thunks)? Мало того, что они непредсказуемы, а потому не всегда ясно, что и где будет исполняться в каком потоке, так эти санки еще требуют некоторой блокировки при первом обращении к санку в много-поточном рантайме (или в Microsoft Research сидят такие кудесники?). Возьмем для примера реализацию Lazy из .NET. Блокировка там присутствует. Ну, а куда без нее?

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

Тем не менее, не оставляю надежды, что люди из Microsoft Research в тысячи раз умнее меня, и что-нибудь придумают эдакое.

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от dave

Значит, предполагаю, что имелся в виду все же хаскель. Тогда вспомним, что в Real World Haskell есть целая глава, посвященная распараллеливанию. И что, у вас не создалось ощущения чего-то неправильного после ее прочтения? Сколько там надо огорода городить чтобы распараллелить! Это раз.

RWH немного устарел, нужно читать черновики будющей книги Семёна Марлоу, сейчас все проще.

Дело в санках (thunks). Мало того, что они непредсказуемы, а потому не всегда ясно, что и где будет исполняться в каком потоке, так эти санки еще требуют некоторой блокировку при первом обращении к санку в много-поточном рантайме (или в Microsoft Research сидят такие кудесники?). Возьмем для примера реализацию Lazy из .NET. Блокировка там присутствует. Ну, а куда без нее?

блокировки нет слава ленивости, используется механизм (gray holes) позволяющий обойтись без блокировок, но возможно приводящий к повторным вычислением, с механизом обнаружения повторных вычислений, если интересно могу ссылки на статьи SPJ дать, но не сегодня.

Хотя учитывая то, что далеко не все, что SPJ понаписал принято в апстрим, возможно щас и не так, но успешные исследования есть.

Это ещё не считая DPH.

qnikst ★★★★★
()
Ответ на: комментарий от monk

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

qnikst ★★★★★
()
Ответ на: комментарий от dave

Значит, предполагаю, что имелся в виду все же хаскель.

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

Никакой конкретный язык не предполагался, у вас СПГС.

Так ты еще из под анонима пишешь?

Это был первый пост. Печеньки кончились.

anonymous
()
Ответ на: комментарий от qnikst

Благодарю за информацию. Ну, я примерно так и предполагал, что возможны повторы, или тогда блокировки.

dave ★★★★★
()
Ответ на: комментарий от anonymous

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

Никакой конкретный язык не предполагался, у вас СПГС.

Ну, я так и думал.

Проблема в том, что если язык гарантирует чистоту, то ему уже желательна ленивость (не охота распинаться на эту тему).

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от monk

затем результат заносим в i.

ненужно нам этих ваших императивных язычков :)

Так, мне надоело.. расскажи мне real-world задачу, в которой нужно или удобнее использовать многопараметричность, во всех языках подобная возможность это сахар над передачей списка. Как понимаешь без многопараметричности данная задача не тривиальна.

qnikst ★★★★★
()
Ответ на: комментарий от dave

не охота распинаться на эту тему

В таком случае я остаюсь в счастливом неведении.

anonymous
()
Ответ на: комментарий от dave

Проблема в том, что если язык гарантирует чистоту, то ему уже желательна ленивость (не охота распинаться на эту тему).

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

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

это сахар над передачей списка.

Ну пусть будет список. Обобщённый на произвольное количество списков foldl возможно в Haskell сделать?

Чтобы можно было потом сделать

f a b c d = a + b + c + d

gen-foldl f 0 [[1 2 3] [4 5 6] [7 8 9]]

monk ★★★★★
()
Ответ на: комментарий от qnikst

во всех языках подобная возможность это сахар над передачей списка.

Если список позволяет элементы различных типов, то да.

monk ★★★★★
()
Ответ на: комментарий от monk

завтра пни, мне сегодня ещё лекцию дописать надо. I что-то вроде forall a . (Type a) => (a -> a) -> Int -> [[a]] -> [[a]]

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

qnikst ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.