【发布时间】:2012-09-07 03:48:15
【问题描述】:
我意识到这可能被认为是一个主观的问题,或者可能是一个离题的问题,所以我希望与其关闭它,不如将它迁移给程序员。
我开始学习 Haskell,主要是为了我自己的启迪,我喜欢很多支持该语言的想法和原则。在参加了一个语言理论课后,我开始对函数式语言着迷,我们在那里玩了 Lisp,而且我听到了很多关于 Haskell 高效的好消息,所以我想我自己去研究一下。到目前为止,我喜欢这门语言,除了一件我无法摆脱的事情:那些母亲 effing 函数签名。
我的专业背景主要是做 OO,尤其是 Java。我工作过的大多数地方都遵循了许多标准的现代教条。敏捷、清洁代码、TDD 等。经过几年的工作,它绝对成为了我的舒适区;特别是“好”代码应该是自我记录的想法。我已经习惯了在 IDE 中工作,其中带有非常描述性签名的冗长冗长的方法名称对于智能自动完成和用于导航包和符号的大量分析工具来说不是问题;如果我可以在 Eclipse 中按 Ctrl+Space,然后通过查看方法的名称和与其参数关联的本地范围变量来推断方法正在做什么,而不是拉起 JavaDocs,我就像一头猪一样高兴。
这显然不是 Haskell 社区最佳实践的一部分。我已经阅读了很多关于这个问题的不同意见,我知道 Haskell 社区认为它的简洁性是一个“专业人士”。我经历过How To Read Haskell,我理解很多决定背后的基本原理,但这并不意味着我喜欢它们;一个字母的变量名等对我来说并不有趣。我承认,如果我想继续使用这种语言,我必须习惯这一点。
但我无法克服函数签名。举个例子,取自Learn you a Haskell[...]'s section on function syntax:
bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!"
| weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
| weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!"
我意识到这是一个愚蠢的例子,它只是为了解释守卫和类约束而创建的,但是如果您要检查 只是该函数的签名,您将不知道它的哪个论点旨在成为重量或高度。即使您使用Float 或Double 代替任何类型,它仍然无法立即辨别。
起初,我以为我会很可爱、聪明、聪明,并尝试使用具有多个类约束的更长类型变量名来欺骗它:
bmiTell :: (RealFloat weight, RealFloat height) => weight -> height -> String
这吐出了一个错误(顺便说一句,如果有人能向我解释这个错误,我将不胜感激):
Could not deduce (height ~ weight)
from the context (RealFloat weight, RealFloat height)
bound by the type signature for
bmiTell :: (RealFloat weight, RealFloat height) =>
weight -> height -> String
at example.hs:(25,1)-(27,27)
`height' is a rigid type variable bound by
the type signature for
bmiTell :: (RealFloat weight, RealFloat height) =>
weight -> height -> String
at example.hs:25:1
`weight' is a rigid type variable bound by
the type signature for
bmiTell :: (RealFloat weight, RealFloat height) =>
weight -> height -> String
at example.hs:25:1
In the first argument of `(^)', namely `height'
In the second argument of `(/)', namely `height ^ 2'
In the first argument of `(<=)', namely `weight / height ^ 2'
不完全理解为什么这不起作用,我开始在谷歌上搜索,我什至发现了这个建议命名参数的小帖子,具体来说,spoofing named parameters via newtype,但这似乎有点多。
没有可接受的方法来制作信息丰富的函数签名吗? “Haskell 方式”只是为了把所有事情都搞砸了吗?
【问题讨论】:
-
顺便说一句,〜在类型级别表示“等于”,所以错误是说身高和体重不是同一类型,除法运算符要求其操作数相同类型。
-
@hzap 这很有意义。谢谢。
-
我使用 Haskell 的次数越多,我就越欣赏“通过
newtype欺骗命名参数”的方法。特别是对于这种width/height问题。它使代码更清晰、更易于维护,并有助于维度分析。如果你做对了,样板文件就会减少,类型签名会更有用,并且错误会更少。 -
您可以采用 TypeFamilies 的方式并将类型相等添加到您的约束中。我不认为这种方式是必要的,或者更清楚,但你可以。
(RealFloat weight, weight ~ height) => ...
标签: haskell syntax coding-style functional-programming