# 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);
;;
_>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) косяк. Сам пару раз на это наталкивался. Кстати, вопрос к знатокам — почему так сделали ?
поправлена разметка. Обратите внимание, что закрывающий тэг — это [/, а не [\ — Кодт
Здравствуйте, chukichuki, Вы писали:
C>>Кстати, вопрос к знатокам — почему так сделали ? C>Вопрос снят. Так сделали из тех же сообращений что и в Си/Си++.
Ну не из тех же, а из похожих.
В Си это сделано из-за конвенции cdecl, по которой самый левый аргумент должен быть на вершине стека. Это нужно для функций с (...), в том числе неявных (необъявленных, либо объявленных только по имени, без сигнатуры). Привет Кернигану и Ричи.
В С++ троеточие могли реализовать как угодно иначе (например, дополнительно передавать неявный параметр — число аргументов), но для совместимости оставили как есть.
А в ML, где вовсю процветает карринг... f x y z = (((f.x).y).z)
Трудный путь состоит в создании замыкания f.x, затем в замыкании (f.x).y, и наконец, в применении ((f.x).y) к z.
Лёгкий путь — в том, чтобы запихать всё на стек и сверху нахлобучить f.
<>
Кажется не очень правильным, что создаётся туча 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-блоками?
К>type 'a maybe = Just of 'a | Nothing;; (* давненько не смотрел на окамл, поэтому заимствую из хаскелла *)
В Окамле есть встроенный тип type 'a option = None | Some of 'a .
Кстати, есть стандартный модуль Sys с готовой функцией readdir : string -> string array
К>Кстати, как обстоят дела с оптимизацией концевой рекурсии с try-блоками?
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.
Здравствуйте, 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, как в Окамле...
Вот уже такая тонкая несовместимость этих двух языков... :о)
Здравствуйте, geniepro, Вы писали:
G>Занятно, в F# печатается xyz, то есть слева направо, а не zyx, как в Окамле... G>Вот уже такая тонкая несовместимость этих двух языков... :о)
А сиплюсплюсники сказали бы просто: unspecified behavior...
Если в спецификации языка это не прописано, то, очевидно, порядок вычисления определён прихотью компилятора.