Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Функциональные языки: общие вопросы > [F#] Простые вопросы


Автор: laMer007 27.12.2011, 20:16
Мне нравится F#. Но большой практики написания программ на нём не было. Писал только вспомогательные тулзы для проектов.

В этой теме хочу задавать вопросы по этому языку.


И так, первые вопросы:
1)Есть ли в F# функция высшего порядка, подобная std::find_if?
2)Как из тела цикла возвращать значение, если искомый результат обнаруживается в конце или в середине цикла? 
Пример, когда результат обнаруживается http://ideone.com/27lqH цикла:
Код
let num n = 
  let t = [|for i in 1..n -> i*2|]
  t.[t.Length-1]
System.Console.Write(num 5)

(Понятно, что тут должен быть поиск в каком-нибудь массиве, но это просто пример).
3)Как правильно получить последний элемент массива, не используя такую убогую конструкцию t.[t.Length-1]?
4)Как вы возвращаете значение из сложной функции с несколькими циклами и ветвлениями, ведь return нет в языке? Мне приходилось делать хак в виде присвоения мутабильной переменной result результата с последующим киданием исключения и отловом около последней строки функции, возвращающей этот сохраненный ранее result. Простите, мой испорченный императивными языками стиль программирования. Как сделать возврат значения из относительно сложной функции правильно по функциональному?

Автор: k0rvin 27.12.2011, 21:40
Цитата(laMer007 @ 27.12.2011,  20:16)
1)Есть ли в F# функция высшего порядка, подобная std::find_if?

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

let rec find_if predicate xs =
    match xs with
    | [] -> None
    | hd::tl ->
        match predicate hd with
        | true  -> Some(hd)
        | false -> find_if predicate tl

как же ты писал тулзы для проектов?

Автор: laMer007 28.12.2011, 01:07
Цитата('k0rvin')
этот ответ легко найти в описании языка 
Не, не легко. Я думаю, в F# обобщённых функций в стандартной библиотеке нет. Про Array.find я знаю. Вы для List свой велосипед написали, но для него такая функция тоже есть. Но это все не то.

Ладно. А что с другими вопросами 2-4? Если они не очень понятны, то я могу объяснить подробнее с конкретными примерами.

Автор: k0rvin 28.12.2011, 08:43
Цитата(laMer007 @ 28.12.2011,  01:07)
Не, не легко. Я думаю, в F# обобщённых функций в стандартной библиотеке нет. Про Array.find я знаю. Вы для List свой велосипед написали, но для него такая функция тоже есть. Но это все не то.

что значит "не то"? и что ты подразумеваешь под обобщенными функциями?

Автор: k0rvin 28.12.2011, 09:11
3) опять же, ищите или пишите функцию last

Добавлено @ 09:23
2,4) думаю смотреть нужно в сторону продолжений (continuations), как-то http://controlflow.tumblr.com/post/2623145951/f-computation-expressions-part-3-cont

Автор: laMer007 28.12.2011, 14:12
Цитата(k0rvin @  28.12.2011,  08:43 Найти цитируемый пост)
что значит "не то"? и что ты подразумеваешь под обобщенными функциями? 
http://liveworkspace.org/code/3f15556304cef72945090bd3cc8ee209:
Код
auto pred=[](int v){return v%4==0;};

int main(void)
{
  int ca[]={1,2,3,7,4,6};
  array<int,6> a={{1,8,3,4,4,6}};
  vector<int> v={1,2,2,4,44,6};
  list<int> l={1,2,8,4,7,6};
  deque<int> d={1,3,3,8,5,6};
  cout<<*find_if(begin(ca), end(ca), pred)<<endl;
  cout<<*find_if(begin(a), end(a), pred)<<endl;
  cout<<*find_if(begin(v), end(v), pred)<<endl;
  cout<<*find_if(begin(l), end(l), pred)<<endl;
  cout<<*find_if(begin(d), end(d), pred)<<endl;
Как видите функция std::find_if работает для любого типа контейнера и всегда тип контейнера можно поменять без необходимости каких либо изменений в коде. В F# же приходится, например по всему коду заменять Array.find на List.find, если поменял тип контейнера с массива на список.


Цитата(k0rvin @  28.12.2011,  09:11 Найти цитируемый пост)
опять же, ищите или пишите функцию last
Не нашёл такой функции что-то для массивов. Понятно, что всё можно написать самому, но наиболее приятно пользоваться языком, если такие мелочи, как last есть в стандартной библиотеке.


Цитата(k0rvin @  28.12.2011,  09:11 Найти цитируемый пост)
2) думаю смотреть нужно в сторону продолжений (continuations) 
http://ideone.com/ti6vI:
Код
let findModM arr n = seq{ for i in arr do if i%n=0 then yield i}
System.Console.Write(findModM [1..50] 5 |> Seq.head)
Лучше не написать?


Цитата(k0rvin @  28.12.2011,  09:11 Найти цитируемый пост)
4) думаю смотреть нужно в сторону продолжений (continuations) 
А можете накатать примерчик решения 4го вопроса, пожалуйста?

Автор: k0rvin 28.12.2011, 14:42
Цитата(laMer007 @ 28.12.2011,  14:12)
http://liveworkspace.org/code/3f15556304cef72945090bd3cc8ee209:
Код
auto pred=[](int v){return v%4==0;};

int main(void)
{
  int ca[]={1,2,3,7,4,6};
  array<int,6> a={{1,8,3,4,4,6}};
  vector<int> v={1,2,2,4,44,6};
  list<int> l={1,2,8,4,7,6};
  deque<int> d={1,3,3,8,5,6};
  cout<<*find_if(begin(ca), end(ca), pred)<<endl;
  cout<<*find_if(begin(a), end(a), pred)<<endl;
  cout<<*find_if(begin(v), end(v), pred)<<endl;
  cout<<*find_if(begin(l), end(l), pred)<<endl;
  cout<<*find_if(begin(d), end(d), pred)<<endl;
Как видите функция std::find_if работает для любого типа контейнера и всегда тип контейнера можно поменять без необходимости каких либо изменений в коде. В F# же приходится, например по всему коду заменять Array.find на List.find, если поменял тип контейнера с массива на список.

а, ты про это... это не "обобщенная функция", ну да не суть. я не знаю как там в F#, но наверное типы Array и List наследуются от одного какого-то общего предка Container или Collection, в котором определена find. иначе придется писать свои обертки.

мб просто преобразовывать в http://msdn.microsoft.com/en-us/library/dd233209.aspx и юзать Seq.find

Добавлено @ 14:45
Цитата(laMer007 @ 28.12.2011,  14:12)
Не нашёл такой функции что-то для массивов. Понятно, что всё можно написать самому, но наиболее приятно пользоваться языком, если такие мелочи, как last есть в стандартной библиотеке.

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

Цитата(laMer007 @ 28.12.2011,  14:12)
Лучше не написать?
А можете накатать примерчик решения 4го вопроса, пожалуйста?

хз, я не шарю в F#

Автор: Kakadu 28.12.2011, 15:29
Цитата

1)Есть ли в F# функция высшего порядка, подобная std::find_if?

Нет, для каждого контейнера (array, list, seq, etc) надо реализовывать свой поиск. естественно, желательно с той же сигнатурой. Тогда типовыводилка тип выведет и будет визуально как в плюсах.
Цитата

2)Как из тела цикла возвращать значение, если искомый результат обнаруживается в конце или в середине цикла? 
Пример, когда результат обнаруживается http://ideone.com/27lqH цикла:
Код
let num n = 
  let t = [|for i in 1..n -> i*2|]
  t.[t.Length-1]
System.Console.Write(num 5)

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

http://ocaml.janestcapital.com/?q=node/91
Цитата

3)Как правильно получить последний элемент массива, не используя такую убогую конструкцию t.[t.Length-1]?

Думаю так и получать. Но мне ни разу это пока не пригождалось. можно ещё List.reverse + List.head
Цитата
4)Как вы возвращаете значение из сложной функции с несколькими циклами и ветвлениями, ведь return нет в языке? Мне приходилось делать хак в виде присвоения мутабильной переменной result результата с последующим киданием исключения и отловом около последней строки функции, возвращающей этот сохраненный ранее result. Простите, мой испорченный императивными языками стиль программирования. Как сделать возврат значения из относительно сложной функции правильно по функциональному?

кидание исключений в Ocaml это норм, в диезе думаю тоже. Мутабельное значение иногда некрасиво. Ну и про yeild_return можно подумать.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)