【问题标题】:Is there a specific type for mathematical functions in Haskell?Haskell 中是否有特定类型的数学函数?
【发布时间】: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]

【问题讨论】:

  • 这看起来像scanlscanl (-) 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) 更通用的类型。

标签: function haskell types


【解决方案1】:

是否有特定的类型来区分这些功能(/,*,+,-)?

我认为没有理由这样做。为什么\x y -> x+y 被认为比\x y -> x + y + 1“更好”。当然,添加两个数字是大多数人会认为更“纯”的东西。但是将自己限制在特定的功能子集是很奇怪的。也有可能某些函数\x y -> f x y - 1“发生”等于(+),除非编译器无法确定。

如果列表包含字符串等,类型检查将确保不能传递对数字进行操作的函数。但是故意进一步限制这一点并不是很有用。你为什么要阻止程序员将你的函数用于不同的目的?

或者还有其他方法可以成功编写此函数吗?

您在这里描述的是scanl :: (b -> a -> b) -> b -> [a] -> [b] 函数。如果我们用scanl f z [x1, x2, ..., xn] 调用scanl,那么我们会得到一个列表[z, f z x1, f (f z x1) x2, ...]scanl 可以定义为:

scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl f = go
    where go z [] = [z]
          go z (x:xs) = z : go (f z x) xs

因此,我们首先发出 accumulator(从初始值开始),然后将累加器“更新”为 f z xz 是旧的累加器,x 是头部列表,并在列表的尾部递归。

【讨论】:

    【解决方案2】:

    如果要限制为这四种操作,自己定义类型即可:

    data ArithOp = Plus | Minus | Times | Div
    
    as_fun Plus = (+)
    as_fun Minus = (-)
    as_fun Times = (*)
    as_fun Div = (/)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 2012-03-12
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 2011-09-17
      • 1970-01-01
      相关资源
      最近更新 更多