如何修改此Haskell平方根函数以获取数组

时间:2015-03-09 23:03:23

标签: arrays haskell recursion

我有一个函数,它将取和int并返回其平方根。但是现在我想修改它,以便它需要一个整数数组并返回一个数组,其中包含第一个数组元素的平方根。我知道Haskell不使用循环所以如何进行这种修改?谢谢。

intSquareRoot :: Int -> Int
intSquareRoot n = try n where
  try i   | i*i > n   = try (i - 1) 
          | i*i <= n  = i

2 个答案:

答案 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