我可以在Erlang中制作自己的Guards吗?

Mar*_*sen 8 erlang guard

我在网上看到了这个代码:

is_char(Ch) ->         
    if Ch < 0 -> false;  
       Ch > 255 -> false;
       true -> true      
    end.

is_string(Str) ->            
    case is_list(Str) of           
    false -> false;           
    true -> lists:all(is_char, Str)
    end.
Run Code Online (Sandbox Code Playgroud)

它是我alwais梦寐以求的守卫,因为它检查输入是否是一个字符串 - 但是,我不允许在erlang中使用它,为什么会这样?是否有解决方法?

我想能够写下这样的东西:

Fun(Str) when is_string(Str) -> Str;
Fun(Int) when is_integer(Int) -> io:format("~w", [Int]).
Run Code Online (Sandbox Code Playgroud)

甚至更好地在消息上使用它.

jur*_*uro 10

您不能在警卫中使用用户定义的功能.这是因为警卫中的功能必须没有副作用(例如io:format在你的功能中使用).在警卫中,您仅限于以下内容:

  • 用于类型测试的BIF( ,is_atom,is_constant,is_float,is_integer,is_list,is_number,is_pid,is_port,is_reference,is_tuple,is_binary,),is_functionis_record
  • 布尔操作符(not,and,or,andalso,orelse,,,;),
  • 关系运算符(>,>=,<,=<,=:=,==,=/=,/=),
  • 算术运算符(+,-,*,div,rem),
  • 位运算符(band,bor,bxor,bnot,bsl,bsr),
  • 是自由的副作用(其他的BIF abs/1,element/2,hd/1,length/1,node/1,2,round/1,size/1,tl/1,trunc/1,self/0)

  • @MartinKristiansen不是真的,因为模块中的任何代码都可以在运行时更改或替换. (6认同)
  • 嗯,似乎检查副作用将是一个非常容易的静态分析技巧... (4认同)
  • @MartinKristiansen那必须是"只有BIF和当前模块中的那些函数,它们只调用当前模块中的BIF和函数,并且不是递归的(以确保它们终止)".这意味着你毕竟不能使用`is_string`作为后卫:) (3认同)

rvi*_*ing 5

在警卫中不允许用户定义的功能的另一个原因是警卫中的错误处理方式与"正常"函数不同.在后卫的错误并不会产生一个例外,它不仅会导致保护本身的失败.

警卫不是真正的表达,而是测试.