【发布时间】:2019-01-16 14:44:02
【问题描述】:
我想编写一个函数,它接受一个数学函数 (/,x,+,-)、一个开头的数字和一个数字列表。然后,它应该返回一个列表。
第一个元素是起始编号,第二个元素是起始编号的值加/减/次/除以给定列表的第一个数字。第三个元素是前一个结果加/减/次/除以给定列表的第二个结果的结果,以此类推。
如果我告诉代码要使用哪个函数,我已经完成了所有工作,但是如果我想让用户输入他想要的数学函数,那么类型就会出现问题。例如,尝试 :t (/) 会给出 Fractional a => a -> a -> a,但如果你把它放在类型的开头,它就会失败。
是否有特定的类型来区分这些函数(/、x、+、-)?还是有另一种方法可以成功编写此函数?
prefix :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix (f) a b = [a] ++ prefix' (f) a b
prefix' :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix' (z) x [] = []
prefix' (z) x y = [x z (head y)] ++ prefix' (z) (head (prefix' (z) x y)) (tail y)
正确的解决方案是这样的:
prefix (-) 0 [1..5]
[0,-1,-3,-6,-10,-15]
【问题讨论】:
-
这看起来像
scanl:scanl (-) 0 [1..5]将返回[0,-1,-3,-6,-10,-15]。但是没有理由将自己局限于数学函数。签名只是scanl :: (b -> a -> b) -> b -> [a] -> [b]。人们可以使用他们想要的任何类型的功能和元素。我不明白你为什么要限制有用的东西?例如,可以写scanl (flip (:)) [] [1,4,2,5]来获取所有颠倒的前缀:[[],[1],[4,1],[2,4,1],[5,2,4,1]]。 -
你只需要更多的括号。
prefix :: (Fractional a, Num a) => (a -> a -> a) -> a -> [a] -> [a]。类似的修改适用于prefix'。但请参阅下面的答案,了解您可以给prefix的 (much) 更通用的类型。