[英]Erlang Beginner: Find Perimeter?
我正在学习Erlang并尝试此处提到的问题,因为
3. Write a function mathStuff:perimeter(Form) which computes the perimeter of different forms. Form can be one of:
{square,Side}
{circle,Radius}
{triangle,A,B,C}
所以,我的解决方案是
-module(mathStuff).
-export([perimeter/1]).
perimeter(Form) ->
case element(1, Form) of
square -> io:format("perimeter for square is ~p~n", [4*element(2, Form)]);
circle -> io:format("perimeter for circle is ~p~n", [2*math:pi()*element(2, Form)]);
triangle -> io:format("perimeter for triangle ~p~n", [element(2, Form) + element(3, Form) + element(4, Form)])
end.
~
当我跑步时我得到
38> c("mathStuff.erl").
{ok,mathStuff}
39> mathStuff:perimeter({circle, 2}).
perimeter for circle is 12.566370614359172
ok
40> mathStuff:perimeter({rectangle, 2}).
** exception error: no case clause matching rectangle
in function mathStuff:perimeter/1 (mathStuff.erl, line 5)
41> mathStuff:perimeter({square, 2}).
perimeter for square is 8
ok
42> mathStuff:perimeter({traingle, 1, 2, 3}).
** exception error: no case clause matching traingle
in function mathStuff:perimeter/1 (mathStuff.erl, line 5)
43> mathStuff:perimeter({triangle, 1, 2, 3}).
perimeter for triangle 6
ok
但这是不正确的,因为我也可以
44> mathStuff:perimeter({triangle, 1, 2, 3, 4}).
perimeter for triangle 6
ok
45>
解决此问题的更好方法是什么,如何才能更具体地说明类型和参数?
第一个错误的原因是您的case ... end
表达式不匹配rectangle
,因此它无法匹配任何内容。 与大多数命令式语言不同,通常需要使用功能性语言中的case
表达式来匹配至少一个子句-否则,该表达式应求值是什么?
解决此问题的一种更惯用的方法是在函数头处进行模式匹配 ,如下所示:
perimeter({square, Side}) ->
io:format("perimeter for square is ~p~n", [4*Side]);
...
perimeter({triangle, A, B, C}) ->
io:format("perimeter for triangle ~p~n", [A + B + C]).
注意,功能子句使用;
分隔;
,最后一个子句以终止.
。
从本质上讲,Erlang无需您从带有element/2
的元组中手动选择字段,而是可以使用模式匹配来“解压缩”该元组。 我认为,这是使用具有代数数据类型的功能语言的最大好处之一。
顺便说一句,即使对于诸如perimeter({triangle, 1, 2, 3, 4})
类的错误调用也能获得正确的结果,原因是您没有使用模式匹配,而是手动选择了元组的相关字段。 您从未检查过元组不长! 模式匹配执行一种输入验证作为副作用,因为这样的表达式如下:
{A, B, C} = {1, 2, 3, 4}
确保因匹配错误而失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.