Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Общие вопросы по программированию, компьютерный форум
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 26.01.2014, 01:29   #111
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,692
По умолчанию

Цитата:
Как в функциональных языках хранятся значения без изменяемых переменных?
fact n tmp | n <= 0 = tmp
| otherwise = fact (n-1) (tmp*n)

fact 5 1 -- вернет 120

Рекурсия и никакой магии )

Точно также в рекурсивную функцию можно затащить getChar и если символ удовлетворителен, то вызывать рекурсивно функцию, после '=' посчитать и вернуть результат.

Код:
calc :: String -> Float
calc = head . foldl f [] . words
   where 
     f :: [Float] -> String -> [Float]
     f (x:y:zs) "+"    = (y + x):zs
     f (x:y:zs) "-"    = (y - x):zs
     f (x:y:zs) "*"    = (y * x):zs
     f (x:y:zs) "/"    = (y / x):zs
     f xs       y      = read y : xs

getExpression :: String -> IO String
getExpression str = do
    c <- getChar
    if c == '=' then return $ reverse str
                else if c `elem` (['+','-','*','/']++['0'..'9']) then getExpression (c:' ':str)
                                                                 else getExpression (str)
main = do
        expr <- getExpression ""
        putStr $ show $ calc expr
Вывод:
Цитата:
$ ./main
1
3
+
=
4.0
хотя проще либо сразу считать при вводе, либо принимать строку целиком.
Код:
calc :: String -> Float
calc = head . foldl f [] . words . filter (`elem` ['+','-','*','/','.',' ']++['0'..'9'])
   where 
     f :: [Float] -> String -> [Float]
     f (x:y:zs) "+"    = (y + x):zs
     f (x:y:zs) "-"    = (y - x):zs
     f (x:y:zs) "*"    = (y * x):zs
     f (x:y:zs) "/"    = (y / x):zs
     f xs       y      = read y : xs
main = do
        expr <- getLine
        print (calc expr)
Вывод
Цитата:
$ ./main
1 2 + 3 * 2 /
4.5

Последний раз редактировалось Kostia; 26.01.2014 в 01:53.
Kostia вне форума Ответить с цитированием
Старый 26.01.2014, 12:18   #112
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Цитата:
Как в функциональных языках хранятся значения без изменяемых переменных?
Ну вот в его примере якобы не переменная с получает символ, но она его не получает, хитрый компилятор дабы не повредить тонкую душевную организацию упоротых функциональщиков - сначала уничтожает пустую переменную потом создает уже с принятым значением, считается что это чистота языка (хотя на самом деле это "черезж*пнутость" языка, ну да ладно, зато свой путь). А параметры функций переменными не считаются (хотя это как копать). Адекватные функциональные языки программирования навроде Лиспа после юзания их в реальных задачах, а не в примерах теоретических сортировок и вычислениях никому ненужных факториалов (нельзя же брать табличные результаты по индексу, это не тру путь) сдались и таки да - есть там всякие циклы и прочие переменные навроде letrec'ов. Потому что производители их трансляторов курят меньше, работают больше и таки да имеют коммерческий профит с математики. И когда им говорят, что язык грязный, хитро улыбаются и считают бабки.
Есть и аналоги монад, только используются они сугубо практически, без преферанса и поэтесс, никто это гениальным решением не называет и не носится как конь с яйцами. Суть такого механизма в стыковании грязных операций с функциями. Например, операция вывода строки на экран не возвращает значения, то есть по сути это процедура, а следующая за ней функция ждет входной параметр, получается коллизия и разрыв мозга функциональщика. Чтобы все было мирно, такие вызовы и оборачивают в то, что в Хаскеле зовется монадой (при этом операция вывода на экран все равно портит воздух и считается грязной)
Ну, а по вопросу, чтобы было проще понять - вот C# есть такие строки immutable (или как там правильно). При работе (если в них вносят какие-то изменения) они каждый раз пересоздаются на куче (точнее не гарантируется, что не пересоздадутся).
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика

Последний раз редактировалось Utkin; 26.01.2014 в 12:31.
Utkin вне форума Ответить с цитированием
Старый 26.01.2014, 16:42   #113
the_deer_one
Участник клуба
 
Аватар для the_deer_one
 
Регистрация: 04.04.2010
Сообщений: 1,554
По умолчанию

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

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


Kostia, хм ну ок, понятно, вообщем то любой гуй через луп и работает.

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

Код:
void Foo(CancellationUnit c)
{
 foreach(var e in blablablabla)
 {
   if(c.ShouldBeCancelled)
     return;
   // чего то там делаем.
 }
}
Utkin
Цитата:
Суть такого механизма в стыковании грязных операций с функциями.
Но вот нафига это нужно мне не очень понятно. Вот мы типа выделили чистые куски. И зойчем, какой нам от этого профит?
the_deer_one вне форума Ответить с цитированием
Старый 26.01.2014, 17:52   #114
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Чисто практический интерес - процедура не возвращает результат, а должна.
Например, пусть print(x) - вывод на экран. Какой результат (и какого типа) вернет print?
Фундаментально программер может написать f(print(x)), по законам жанра это будет правдой. В реальности же будет открыт портал в Матрицу. Чтобы такого не было пишется что-то типа (абстрактно, разумеется, в каждом языке свой синтаксис):
f(
begin(
print(x)
z(y)
)
)
Получается что f вместо print(х) получит результат z(y). Как и Kostia программа вызов грязной функции не увидела. Есть конечно различные варианты, но суть в том, что есть какие-то соглашения, которые закрывают глаза на грязную функцию, чтобы потом можно было сказать, что ничего такого и не было.
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 27.01.2014, 09:47   #115
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,692
По умолчанию

Цитата:
что есть какие-то соглашения, которые закрывают глаза на грязную функцию, чтобы потом можно было сказать, что ничего такого и не было.
Нужно просто обмануть компилятор )
Код:
f(print(x))
Это возможно, т.к. print(x) вернет IO (), пустой кортеж завернутый в монаду IO. При этом IO как контейнер интересен тем, что он односторонний, из него нельзя вытащить значение, только положить единожды. Или по другому, из IO вытащить значение просто так невозможно, можно только взять что там лежит, что-то с этим сделать и обязательно положить обратно, иначе никак.
Цитата:
То есть например сначала баба была с одним мужиком, потом забыла про него, и ушла к другому. Вот это вот чистота, второй мужик может делать с ней всё что угодно и не думать про первого мужика. А первый мужик сплавлять бабу и не бояться что она вернётся. У каждого получается своя личная баба.
Баба не может забыть, объекты неизменны и присвоить одной и той же переменной разные значения невозможно, присвоение(связывание) происходит единожды и навсегда. Другое дело, что мы создаем другую бабу и пихаем ее в функцию, но это уже совсем другая баба =)
При этом монада, это просто класс типов, который требует определения пары функций:
Код:
    return :: a -> M a
    (>>=)  :: M a -> ( a -> M b ) -> M b
(>>) будет выведена автоматически.
При этом монада будет считаться монадой только после соблюдения определенных правил, который компилятор самостоятельно проверить не способен. (для аппликативных функторов тоже есть правила)
IO как раз такия является функтором:
Код:
instance Functor IO where
    fmap f action = do
    result <- action
    return (f result)
Цитата:
Сообщение от Изучай Haskell во имя добра!
Результатом отображения действия ввода-вывод с помощью чего-либо будет действие ввода-вывода, так что мы сразу же используем синтаксис do для склеивания двух действий и создания одного нового. В реализации для fmap мы создаем новое действие ввода-вывода, которое сначала выполняет первоначальное действие ввода-вывода, давая результату имя result. Затем мы выполняем return (f result). Вспомните, что return — это функция, создающая действие ввода-вывода, которое ничего не делает, а только возвращает что-либо в качестве своего результата.
Цитата:
В шарпе мы можем передать переменную, через которую подадим функции команду сворачивать деятельность.
Модель акторов которая используется в Erlang и является частью языка, это красиво демонстрирует:
Код:
start_server() ->
    spawn(?MODULE, server_loop, [0]). % This function calls the server_loop function in a new thread.

server_loop(Count) ->
    receive % Wait for messages
        {From, quit} ->
            io:fwrite("Received quit command from ~p~n", [From]),
            ok;
        {From, Message} ->
            io:fwrite("~p: Server ~p received message ~p from ~p~n", [Count, self(), Message, From]), % Display the message we received.
            ?MODULE:server_loop(Count); % Call the same function again to wait for an other message.
        _ ->
            throw(unexpected_message) % Долой непонятные сообщения =)
    end.
start_server стартует поток server_loop и возвращает его id, используя этот id, потоку можно посылать сообщения.(id гарантировано для любого порожденного потока будет уникальным)
Код:
PID = start_server() %стартанули
PID ! {self(), "Server, show this message please!"} %послали сообщение
PID ! {self(), quit} %послали атом quit и остановили поток
При этом для Erlang 100k потоков как 2 пальца. Искусственное ограничение на кол-во потоков около 2-х миллионов, но его можно изменить на любое свое )

Последний раз редактировалось Kostia; 27.01.2014 в 10:14.
Kostia вне форума Ответить с цитированием
Старый 27.01.2014, 14:03   #116
the_deer_one
Участник клуба
 
Аватар для the_deer_one
 
Регистрация: 04.04.2010
Сообщений: 1,554
По умолчанию

Ну это типа очереди комманд, а очередь та же переменная. Ну ладно, на каждый неудобный случай там есть свой костыль.

А зачем всётаки эта чистота. Ну типа у нас компилятор понимает какая часть функций чистая, а какая нет. А зачем. Мне на ум приходит только вычисление процента покрытия кода тестами
the_deer_one вне форума Ответить с цитированием
Старый 27.01.2014, 14:37   #117
Utkin
Старожил
 
Аватар для Utkin
 
Регистрация: 04.02.2009
Сообщений: 17,351
По умолчанию

Цитата:
А зачем.
Затем что исполняемый код зависит от типа используемых данных. Ситуации описанные выше не позволяют определить какой тип там получается (или его определение нудно).
Маньяк-самоучка
Utkin появился в результате деления на нуль.
Осторожно! Альтернативная логика
Utkin вне форума Ответить с цитированием
Старый 27.01.2014, 16:35   #118
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,692
По умолчанию

Цитата:
А зачем всётаки эта чистота.
А зачем в ООП инкапсуляция?
Kostia вне форума Ответить с цитированием
Старый 27.01.2014, 17:12   #119
MihalNik
МегаМодератор
СуперМодератор
 
Регистрация: 27.11.2012
Сообщений: 5,711
По умолчанию

Цитата:
Сообщение от the_deer_one Посмотреть сообщение
Ну это типа очереди комманд, а очередь та же переменная. Ну ладно, на каждый неудобный случай там есть свой костыль. А зачем всё-таки эта чистота. Ну типа у нас компилятор понимает какая часть функций чистая, а какая нет. А зачем. Мне на ум приходит только вычисление процента покрытия кода тестами
Ну, вначале императивный код затачивался под конкретную архитектуру. Потом эту задачу переложили на компилятор. Потом развились параллельные архитектуры. А чтобы безопасно распараллелить код, надо определить грязные точки ввода/вывода.

Цитата:
Сообщение от Kostia Посмотреть сообщение
А зачем в ООП инкапсуляция?
Сокрытие пр-в имен есть не только в ООП, это принцип структурного прог-ия вообще, просто ООП поддерживает спец. вид структурирования и соответствующую ему инкапсуляцию. В императивном ЯП, не заметив модификации переменной, можно легко совершить ошибку. Подобное a= ++b в общем случае не есть хорошо.
Поэтому есть пароноидальный const, singleton и пр. (я лично бы предпочел подстветку модифицируемых элементов в коде, блэкджек и ш***)

В данном конкретном случае опыт предыдущих ЯП использовался мало, а математической теории - много. Поэтому получилось "оригинально", но мало пригодно:
В мат. нотации нельзя написать a = a+1;
Надо a1= a+1;
Новое значение => новое имя.
Ну а монады просто дань моде, убившая синтаксис.

Kostya считает, что это имеет какое-то отношение к теме
Благими намерениями устлана дорога на programmersforum.ru

Последний раз редактировалось MihalNik; 27.01.2014 в 17:19.
MihalNik вне форума Ответить с цитированием
Старый 27.01.2014, 17:52   #120
Kostia
Участник клуба
 
Аватар для Kostia
 
Регистрация: 21.11.2007
Сообщений: 1,692
По умолчанию

Цитата:
Поэтому есть пароноидальный const, singleton и пр. (я лично бы предпочел подстветку модифицируемых элементов в коде, блэкджек и ш***)
О да, я бы тоже не отказался )
Код:
const A method(const &A, const &B) const;
const const const
Цитата:
Ну это типа очереди комманд, а очередь та же переменная.
Где переменная? Очередность достигается за счет зависимости по аргументам.
Код:
get2chars i0 = [a,b]  where (a,i1) = getchar i0
                            (b,i2) = getchar i1
Сначала будет получен символ a, потом b. getchar принимает какое-то значение, и возвращает кортеж из символа и другого значения(отличного от попавшего в него). Чтобы второй getchar выполнился, ему нужно получить i1, а его возвращает первый getchar.
Цитата:
В данном конкретном случае опыт предыдущих ЯП использовался мало, а математической теории - много.
Конкретно в Хаскеле, да, хотя фп появилось почти одновременно с императивными языками и до }{аскеля было много фп языков, их писали все кому не лень =). Философский вылизанный язык. Если посмотреть на тот же Erlang который изначально был заточен под конкретную задачу выглядит монструозно и неповоротлив во многих задачах, а также медленный. Например в основную цель не попадала работа с вещественными числами, они работают медленно, проблема со строками. Была попытка сделать типизацию(статическую) как в Хаскеле, но столкнулись серьезными ошибками прошлого )
Но в Erlang меня сначала поразила возможность без проблем запустить программу сразу на нескольких компьютерах, т.е. рапараллелить, объединить несколько машин в одно информационное пространство. Горячее обновление, т.е. обновление частей уже работающей программы и т.д.

Последний раз редактировалось Kostia; 27.01.2014 в 18:00.
Kostia вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
вопросик самым опытным :-) Doholyan Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 1 25.08.2009 17:13
Проблема с синтаксисом? Geddar PHP 1 30.06.2008 16:44
Казус с синтаксисом???... Sota Общие вопросы C/C++ 6 17.07.2007 19:15