[erlang-questions] Why it is a illegal guard expression?

Richard O'Keefe ok@REDACTED
Thu Feb 25 02:47:05 CET 2010


On Feb 24, 2010, at 4:42 PM, 钱晓明 wrote:

> Hi, I am a newer of erlang. I wrote a module to find all files(no  
> directory)
> under a directory, including its subdirectory:
> -module(lib_test).
> -export([list_files/1]).
>
> list_files(Path)->
>    {ok, FileList} = file:list_dir(Path),
>    process_filelist(FileList, []).
>
> process_filelist([File|FileList], Files)->
>    if
>       filelib:is_dir(File) ->
>        {ok, NewFileList} = file:list_dir(File),
>        process_filelist(NewFileList, Files);
>       true ->
>        process_filelist(FileList, [File|Files])
>    end;
> process_filelist([], Files) ->
>    Files.
>
> But I fail to compile this file, because " filelib:is_dir(File) ->" is
> illegal guard expression. So Why it is illegal? What should I write?

What did you find when you looked in the reference manual?
What does it say you are allowed to use in a guard?

You should write

     process_file_list([Path|Paths], Files) ->
         case filelib:is_dir(Path)
           of true ->
	     {ok, Children} = file:list_dir(Path),
	     Children_Paths = [filename:join(Path, Child) || Child <-  
Children],
	     process_file_list(Paths,
		process_file_list(Children_Paths, Files))
	   ; false ->
	     process_file_list(Paths, [Path|Files])
	end;
     process_file_list([], Files) ->
	Files.

There are four issues.
(1) If your function is processing [A,B,C] and A is a directory,
     it will completely forget about B and C.  I suspect that you
     don't want that.  If you do, you really really need to make
     that explicit in a comment.
(2) The documentation for file:list_dir/1 does not make it clear
     whether you get just the simple name of each child or the
     simple name with the directory prefix.  The second is what
     you *need* if you want to recursively walk the directory
     tree; the first is what you *get*.
(3) Not everything that isn't a directory is a file.
     If you simply define a file to be anything that is not a
     directory, OK, but if you think a "file" is what UNIX calls
     a "regular file", that's not what you get.  Arguably you
     should be using
	case <look for it yourself>(Path)
	  of directory -> ...
	   ; file -> ...
	   ; socket -> ...
	   ; device -> ...
	   ; other -> ...
	   ; {error,_} -> ...
	end
     This is an unexpected benefit of the limitations of guards;
     Booleans-and-ifs are very often the wrong thing to do anyway.
(4) I dare say that you understand perfectly well that a single
     directory you're not allowed to search inside will bring your
     whole function crashing down rather than just skipping that
     directory, but it's definitely worth a comment to remind
     less savvy readers.





More information about the erlang-questions mailing list