我是Haskell的初学者.
根据我的学校资料在功能定义中使用的惯例实际上如下
function_name arguments_separated_by_spaces = code_to_do
例如:
f a b c = a * b +c
Run Code Online (Sandbox Code Playgroud)
作为一名数学学生,我习惯于使用如下的功能
function_name(arguments_separated_by_commas)= code_to_do
例如:
f(a,b,c) = a * b + c
Run Code Online (Sandbox Code Playgroud)
它在Haskell工作.
我怀疑它是否适用于所有情况?
我的意思是我可以在Haskell函数定义中使用传统的数学约定吗?
如果错了,在哪些特定情况下会出错?
提前致谢 :)
Chr*_*lor 13
假设您要定义一个函数来计算右三角形的hypoteneuse的平方.以下任一定义均有效
hyp1 a b = a * a + b * b
hyp2(a,b) = a * a + b * b
Run Code Online (Sandbox Code Playgroud)
但是,它们的功能不一样!您可以通过查看GHCI中的类型来判断
>> :type hyp1
hyp1 :: Num a => a -> a -> a
>> :type hyp2
hyp2 :: Num a => (a, a) -> a
Run Code Online (Sandbox Code Playgroud)
以hyp2第一(和忽略Num a =>的部分现在)类型告诉你的函数取一对(a, a)并返回另一个a(例如,它可能需要两个整数并返回另一个整数,或一对实数和返回另一个实数).你这样使用它
>> hyp2 (3,4)
25
Run Code Online (Sandbox Code Playgroud)
请注意,括号在这里不是可选的!他们确保参数的类型正确,一对as.如果你不包含它们,你会收到一个错误(现在看起来可能会让你感到困惑,但请放心,当你学会了类型类时它会有意义).
现在看hyp1一种读取类型的方法a -> a -> a是它需要两种类型的a东西并返回其他类型的东西a.你这样使用它
>> hyp1 3 4
25
Run Code Online (Sandbox Code Playgroud)
现在,如果你,你会得到一个错误做包括括号!
所以首先要注意的是,使用该函数的方式必须与您定义它的方式相匹配.如果使用parens定义函数,则每次调用它时都必须使用parens.如果在定义函数时不使用parens,则在调用它时不能使用它们.
因此,似乎没有理由偏爱另一个 - 这只是一个品味问题.但实际上,我认为有是一个很好的理由,更喜欢一个比其他的,你应该更喜欢的风格没有括号.有三个很好的理由:
它看起来更干净,如果你没有让页面混乱的话,你的代码也更容易阅读.
如果你在任何地方都使用parens,你将会受到性能影响,因为每次使用该函数时都需要构造和解构一对(尽管编译器可能会优化它 - 我不确定).
你想获得currying的好处,也就是部分应用的函数*.
最后一点有点微妙.回想一下,我说理解类型函数的一种方法a -> a -> a是它需要两种类型的东西a,然后返回另一种类型a.但还有另一种方式来阅读这种类型,即a -> (a -> a).这意味着完全相同的事情,因为->运算符在Haskell中是正确关联的.解释是该函数采用单个函数a,并返回一个类型的函数a -> a.这允许您只为函数提供第一个参数,并稍后应用第二个参数,例如
>> let f = hyp1 3
>> f 4
25
Run Code Online (Sandbox Code Playgroud)
这在各种情况下实际上都是有用的.例如,map函数允许您将某些函数应用于列表的每个元素 -
>> :type map
map :: (a -> b) -> [a] -> [b]
Run Code Online (Sandbox Code Playgroud)
假设你有(++ "!")任何功能可以增加任何一个爆炸声String.但你有列表,Strings并且你希望它们都以爆炸结束.没问题!您只是部分应用该map功能
>> let bang = map (++ "!")
Run Code Online (Sandbox Code Playgroud)
现在bang是**型的功能
>> :type bang
bang :: [String] -> [String]
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用它
>> bang ["Ready", "Set", "Go"]
["Ready!", "Set!", "Go!"]
Run Code Online (Sandbox Code Playgroud)
非常有用!
我希望我已经说服你,你学校教育材料中使用的惯例有一些非常可靠的理由被使用.作为一个拥有数学背景的人,我可以看到使用更"传统"语法的吸引力,但我希望随着你在编程过程中的进步,你将能够看到改变为最初有点的东西的优势对你不熟悉
*对于学生的注意事项 - 我知道currying和部分应用并不完全相同.
**实际上GHCI会告诉你类型,bang :: [[Char]] -> [[Char]]但因为这String是同义词的同义词[Char].