[erlang-questions] illegal guard expression: filelib:is_dir(H)
Richard O'Keefe
ok@REDACTED
Mon Feb 15 03:18:50 CET 2010
On Feb 14, 2010, at 11:51 PM, Kay Kay wrote:
> I have a function along the following lines
>
> do_process_elements([], _) -> [];
> do_process_elements([H | _], Fn) ->
> if
> filelib:is_dir(H) ->
> process_directory(H, Fn);
> true ->
> process_file(H, Fn)
> end.
>
>
> When I compile - I get the following error, where the line number
> refers to - filelib:is_dir(H) function.
>
> ./test.erl:23: illegal guard expression
>
> Given that filelib:is_dir(H) returns true / false - I thought this
> would fit in here as a predicate. What could be going wrong ?
Guards are NOT expressions. They are in a special mini-language
that allows only a small fixed set of guard functions and tests.
Amongst other things, guards are not allowed to have side effects.
This is explained in Erlang books and the Erlang reference manual.
In this case, the answer is simple:
do_process_elements([H|T], Fn) ->
case filelib:is_dir(H)
of true -> process_directory(H, Fn)
; false -> process_file(H, Fn)
end.
We had a thread about this last year. One point in that thread
was that very often you think of something as having two
outcomes and map it to a Boolean, but *really* there are more
outcomes, so you should be using a 'case' anyway.
This is a perfect example of that.
There are some issues with filelib.
For example, file_lib:is_file(F) is true when F is a file or a
directory. If that hasn't led to mistakes, I'll be surprised.
If you look for a "file", there are at least four outcomes:
- there is a file system binding for that name
and it is a directory
- there is a file system binding for that name
and it is a regular file
- there is a file system binding for that name
and it is something else (character special,
block special, symbolic link, named pipe, door, ...)
[PS: can anyone explain to me, as to a very small
child, what a Solaris "door" is?]
- there is no file system binding for that name
and of course with symbolic links there is the issue of
whether you want to see them or not. For the sake of argument,
one simple interface might be
filelib2:file_type(FileName) ->
directory
regular
other
missing
You should probably be using something like
do_process_elements([H|T], Fn) ->
case filelib2:file_type(H)
of directory -> process_directory(H, Fn)
; regular -> process_file(H, Fn)
; other -> process_other(H, Fn)
; missing -> process_missing(H, Fn)
end.
I have come to regard attempts to use 'if' with user-defined tests
as a "code smell". They're not always misguided, but they indicate
an underlying problem often enough that I am now _glad_ that 'if'
doesn't allow them.
More information about the erlang-questions
mailing list