[ocaml]
От: _rasta  
Дата: 27.06.08 05:39
Оценка:
день добрый

хочу прочитать список файлов в директории.

так работает:
# let get_files_list pwd =
  let rec g p =
    try
      let dsc = (Unix.readdir p) in
        dsc :: (g p)
    with End_of_file ->
    Unix.closedir p;
    [] in

  (g (Unix.opendir pwd));;

# get_files_list (Unix.getcwd ());;
- : string list = ["file1"; "file1"; "file3"]


так нет:
let get_files_list pwd =
  let rec g p =
    try
      (Unix.readdir p) :: (g p);
    with End_of_file ->
    Unix.closedir p;
    [] in

    g (Unix.opendir pwd);
;;


вопрос: почему?
хочется без лишней переменной...

--
-- via knode --
Posted via RSDN NNTP Server 2.1 beta
поправлена разметка — Кодт
Re: [ocaml]
От: _rasta  
Дата: 27.06.08 05:40
Оценка:
_rasta wrote:

ух... тему забыл... виноват.

--
-- via knode --
Posted via RSDN NNTP Server 2.1 beta
Re: [ocaml]
От: chukichuki  
Дата: 27.06.08 06:55
Оценка:
Здравствуйте, _rasta, Вы писали:

_>так нет:

_>
_>let get_files_list pwd =
_>  let rec g p =
_>    try
_>      (Unix.readdir p) :: (g p);
_>    with End_of_file ->
_>    Unix.closedir p;
_>    [] in

_>    g (Unix.opendir pwd);
_>;;
_>



Вот очень показательный пример


let foo x y z = ()

let _ = foo (print_string "x"; flush stdout; 1) (print_string "y"; flush stdout; 2) (print_string "z"; flush stdout; 3)


надо обратить внимание в каком порядке вычисляются аргументы foo. Справа на лево. У тебя из-за этого в (Unix.readdir p) :: (g p) косяк. Сам пару раз на это наталкивался. Кстати, вопрос к знатокам — почему так сделали ?

поправлена разметка. Обратите внимание, что закрывающий тэг — это [/, а не [\ — Кодт
Re[2]: [ocaml]
От: chukichuki  
Дата: 27.06.08 07:00
Оценка:
Здравствуйте, chukichuki, Вы писали:

C>Кстати, вопрос к знатокам — почему так сделали ?


Вопрос снят. Так сделали из тех же сообращений что и в Си/Си++.
Re[3]: [ocaml]
От: Кодт Россия  
Дата: 27.06.08 12:31
Оценка:
Здравствуйте, chukichuki, Вы писали:

C>>Кстати, вопрос к знатокам — почему так сделали ?

C>Вопрос снят. Так сделали из тех же сообращений что и в Си/Си++.

Ну не из тех же, а из похожих.

В Си это сделано из-за конвенции cdecl, по которой самый левый аргумент должен быть на вершине стека. Это нужно для функций с (...), в том числе неявных (необъявленных, либо объявленных только по имени, без сигнатуры). Привет Кернигану и Ричи.
В С++ троеточие могли реализовать как угодно иначе (например, дополнительно передавать неявный параметр — число аргументов), но для совместимости оставили как есть.

А в ML, где вовсю процветает карринг... f x y z = (((f.x).y).z)
Трудный путь состоит в создании замыкания f.x, затем в замыкании (f.x).y, и наконец, в применении ((f.x).y) к z.
Лёгкий путь — в том, чтобы запихать всё на стек и сверху нахлобучить f.
Перекуём баги на фичи!
Re: [ocaml]
От: Кодт Россия  
Дата: 27.06.08 12:45
Оценка:
Здравствуйте, _rasta, Вы писали:

<>
Кажется не очень правильным, что создаётся туча try-кадров.
Может быть, лучше было так
type 'a maybe = Just of 'a | Nothing;; (* давненько не смотрел на окамл, поэтому заимствую из хаскелла *)

let maybe_readdir p =
    try
        Just (Unix.readdir p)
    with
        End_of_file -> Nothing
    ;;

let rec readdirs p =
    match maybe_readdir p
    with
        Just s -> s :: readdirs p
    |    Nothing -> []
    ;;

let get_files pwd =
    let p = Unix.opendir pwd in
    let dirs = readdir p in
    Unix.closedir p;
    dirs
    ;;

В этом случае бросок чего-то отличного от End_of_file вылетит из maybe_readdir и сразу же окажется где-то в обработчике за пределами get_files.
А у тебя он будет прыгать, разматывая все вызовы функции g.

Кстати, как обстоят дела с оптимизацией концевой рекурсии с try-блоками?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: [ocaml]
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 27.06.08 13:27
Оценка:
Здравствуйте, Кодт, Вы писали:


К>type 'a maybe = Just of 'a | Nothing;; (* давненько не смотрел на окамл, поэтому заимствую из хаскелла *)


В Окамле есть встроенный тип type 'a option = None | Some of 'a .
Кстати, есть стандартный модуль Sys с готовой функцией readdir : string -> string array

К>Кстати, как обстоят дела с оптимизацией концевой рекурсии с try-блоками?


Плохо — не концевая.
Re[3]: [ocaml]
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 27.06.08 13:36
Оценка:
Вариант с концевой рекурсией:
open ExtList;;
let get_files_list pwd =
  let handle = Unix.opendir pwd in
  let rec loop lst = 
    match(try Some(Unix.readdir handle) with End_of_file->None) with 
    | Some s-> loop (s::lst)
    | None -> Unix.closedir handle; lst
  in List.rev (loop []);;
    
List.iter (Printf.printf "%s ") (get_files_list ".");;


Без ExtList будет проблема с неконцевой рекурсией в List.rev.
Re[4]: [ocaml]
От: Кодт Россия  
Дата: 27.06.08 14:08
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Вариант с концевой рекурсией:


Да, хаскелл отучает от энергично-хвостовой рекурсии...

DM>Без ExtList будет проблема с неконцевой рекурсией в List.rev.


Почему? Казалось бы
let rev lst =
    let rec
      loop ([],dst) = dst
    | loop ((x::xs),dst) = loop (xs,(x::dst))
in loop (lst,[])
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: [ocaml]
От: geniepro http://geniepro.livejournal.com/
Дата: 27.06.08 14:09
Оценка:
Здравствуйте, chukichuki, Вы писали:

C>Вот очень показательный пример


let foo x y z = ()

let _ = foo (print_string "x"; flush stdout; 1) (print_string "y"; flush stdout; 2) (print_string "z"; flush stdout; 3)


C>надо обратить внимание в каком порядке вычисляются аргументы foo. Справа на лево. У тебя из-за этого в (Unix.readdir p) :: (g p) косяк. Сам пару раз на это наталкивался. Кстати, вопрос к знатокам — почему так сделали ?


Занятно, в F# печатается xyz, то есть слева направо, а не zyx, как в Окамле...
Вот уже такая тонкая несовместимость этих двух языков... :о)
Re[5]: [ocaml]
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 27.06.08 15:32
Оценка:
DM>>Без ExtList будет проблема с неконцевой рекурсией в List.rev.

К>Почему?


Это я перепутал с другой функцией, беру свои слова обратно. List.rev нормальная:
let rec rev_append l1 l2 =
  match l1 with
    [] -> l2
  | a :: l -> rev_append l (a :: l2)

let rev l = rev_append l []
Re[3]: [ocaml]
От: Кодт Россия  
Дата: 27.06.08 18:26
Оценка:
Здравствуйте, geniepro, Вы писали:

G>Занятно, в F# печатается xyz, то есть слева направо, а не zyx, как в Окамле...

G>Вот уже такая тонкая несовместимость этих двух языков... :о)

А сиплюсплюсники сказали бы просто: unspecified behavior...

Если в спецификации языка это не прописано, то, очевидно, порядок вычисления определён прихотью компилятора.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.