我有一个函数,它将取和int并返回其平方根。但是现在我想修改它,以便它需要一个整数数组并返回一个数组,其中包含第一个数组元素的平方根。我知道Haskell不使用循环所以如何进行这种修改?谢谢。
intSquareRoot :: Int -> Int
intSquareRoot n = try n where
try i | i*i > n = try (i - 1)
| i*i <= n = i
答案 0 :(得分:8)
“循环一些集合”的想法,将每个结果放在其输入的相应插槽中,这是一个有点微不足道,非常常见的模式。模式适用于OO程序员。在Haskell中,当有一个模式时,我们想要抽象,即给它一个简单的名称,我们总是可以重复使用而无需额外的样板。
这个特殊的“模式”是仿函数操作 1 。对于列表,它被称为
map :: (a->b) -> [a]->[b]
更普遍(例如,它也适用于真实数组;列表实际上不是数组),
class Functor f where
fmap :: (a->b) -> f a->f b
所以不要定义额外的功能
intListSquareRoot :: [Int] -> [Int]
intListSquareRoot = ...
您只需在您想要使用该功能的地方使用map intSquareRoot
。
当然,您也可以定义intSquareRoot
的“提升”版本,
intListSquareRoot = map intSquareRoot
但是,只需简单地在您需要的地方内联map
电话即可获得任何结果。
那说...当然有理由怀疑map
本身是如何运作的。好吧,你可以通过递归手动“循环”列表:
map' :: (a->b) -> [a]->[b]
map' _ [] = []
map' f (x:xs) = f x : map' f xs
现在,您可以在此处内联您的特定功能
intListSquareRoot' :: [Int] -> [Int]
intListSquareRoot' [] = []
intListSquareRoot' (x:xs) = intSquareRoot x : intListSquareRoot' xs
这不仅比快速插入map
魔术词更笨拙和笨拙,它通常也会更慢:GHC等编译器在处理更高级别的概念时可以做出更好的优化 2 ,例如折叠,而不是必须使用手动定义的递归反复工作。
1 不要混淆许多C ++程序员称之为“functor”。 Haskell使用correct mathematical sense中的单词,它来自类别理论。
2 这就是为什么Matlab和APL等语言实际上为特殊应用程序实现了不错的性能,尽管它们是动态类型的解释语言:它们具有“向量循环”的特殊情况“硬编码成他们的语法。 (不幸的是,这几乎是唯一他们可以做得好的事情......)
答案 1 :(得分:4)
您可以使用map
:
arraySquareRoot = map intSquareRoot