【问题标题】:Haskell / Miranda: Find the type of the functionHaskell / Miranda:查找函数的类型
【发布时间】:2012-05-09 13:35:53
【问题描述】:

简介:这是 Miranda 考试的过去试题,但语法与 Haskell 非常相似。

问题:以下表达式的类型是什么,它的作用是什么? (定义 函数长度和交换如下所示)。

(foldr (+) 0) . (foldr ((:) . length . (swap (:) [] )) [])

length [] = 0

length (x:xs) = 1 + length xs

swap f x y = f y x

注意:

请随时用 haskell 语法回复 - 很抱歉将星星用作多型,但我不想将它错误地翻译成 haskell。基本上,如果一个变量具有 * 类型,而另一个具有 * 则意味着它们可以是任何类型,但它们必须是相同的类型。如果一个有**,则意味着它可以但不需要与*具有相同的类型。我认为它对应于 haskell 用法中的 a、b、c 等。

我目前的工作

从长度的定义你可以看到它找到了任何东西的列表的长度,所以这给出了

length :: [*] -> num.

从定义我认为 swap 接受一个函数和两个参数,并产生两个参数交换的函数,所以这给出了

swap :: (* -> ** -> ***) -> ** -> [*] -> ***

foldr 接受一个二进制函数(如加号)一个起始值和列表,并使用该函数从右到左折叠列表。这给了

foldr :: (* -> ** -> **) -> ** -> [*] -> **)

我知道在函数组合中它是右关联的,因此例如第一个点 (.) 右侧的所有内容都需要生成一个列表,因为它将作为第一个 foldr 的参数给出。

foldr 函数输出单个值(折叠列表的结果),所以我知道返回类型将是某种多型,而不是多型列表。

我的问题

我真的不确定从这里去哪里。我可以看到 swap 需要接受另一个参数,那么这个部分应用是否暗示整个事物是一个函数?我很困惑!

【问题讨论】:

  • 安装Haskell Platform,用GHCi测试一下,有什么问题? Prelude> let swap = flipPrelude> :t (foldr (+) 0) . (foldr ((:) . length . (swap (:) [] )) [])(foldr (+) 0) . (foldr ((:) . length . (swap (:) [] )) []) :: [a] -> Int.
  • 感谢您的回答,但我也希望能在了解如何到达那里得到一些帮助!虽然知道答案肯定会帮助我尝试找出那里的路线,但再次感谢
  • 嗯,您可以在 GHCi 中测试完整子表达式的任何子表达式,这应该可以让您了解到达那里的方法。

标签: haskell types functional-programming type-inference miranda


【解决方案1】:

让我们一步一步来。

length 函数显然具有您描述的类型;在 Haskell 中是 Num n => [a] -> n。等效的 Haskell 函数是 length(它使用 Int 而不是任何 Num n)。

swap 函数接受一个函数来调用并反转它的前两个参数。你没有得到完全正确的签名;这是(a -> b -> c) -> b -> a -> c。等效的 Haskell 函数是 flip

foldr 函数具有您描述的类型;即(a -> b -> b) -> b -> [a] -> b。等效的 Haskell 函数是 foldr

现在,让我们看看主表达式中每个子表达式的含义。

表达式swap (:) [] 采用(:) 函数并交换其参数。 (:) 函数的类型为 a -> [a] -> [a],因此 swapping 它产生 [a] -> a -> [a];整个表达式因此具有类型a -> [a],因为交换函数应用于[]。生成的函数的作用是在给定项目的情况下构造一个项目列表。

为简单起见,让我们将这部分提取到一个函数中:

singleton :: a -> [a]
singleton = swap (:) []

现在,下一个表达式是(:) . length . singleton(:) 函数仍然有 a -> [a] -> [a] 类型; (.) 函数的作用是组合函数,所以如果你有一个函数 foo :: a -> ... 和一个函数 bar :: b -> afoo . bar 将具有类型 b -> ...。因此,表达式(:) . length 的类型为Num n => [a] -> [n] -> [n](请记住length 返回一个Num),而表达式(:) . length . singleton 的类型为Num => a -> [n] -> [n]。结果表达式的作用有点奇怪:给定 a 类型的任何值和一些列表,它将忽略 a 并将数字 1 添加到该列表中。

为简单起见,让我们用它来做一个函数:

constPrependOne :: Num n => a -> [n] -> [n]
constPrependOne = (:) . length . singleton

您应该已经熟悉foldr。它使用函数对列表执行右折叠。在这种情况下,它会在每个元素上调用constPrependOne,因此表达式foldr constPrependOne [] 只是构造一个与输入列表长度相等的列表。所以让我们用它来做一个函数:

listOfOnesWithSameLength :: Num n => [a] -> [n]
listOfOnesWithSameLength = foldr constPrependOne []

如果你有一个列表[2, 4, 7, 2, 5],你会在申请listOfOnesWithSameLength时得到[1, 1, 1, 1, 1]

那么,foldr (+) 0 函数是另一个右折叠函数。相当于Haskell中的sum函数;它对列表的元素求和。

那么,我们来做一个函数:

sum :: Num n => [n] -> n
sum = foldr (+) 0

如果你现在编写函数:

func = sum . listOfOnesWithSameLength

... 你得到结果表达式。给定一些列表,它会创建一个仅由 1 组成的等长列表,然后对该列表的元素求和。换句话说,它的行为与length 完全一样,只是使用了更慢的算法。所以,最终的功能是:

inefficientLength :: Num n => [a] -> n
inefficientLength = sum . listOfOnesWithSameLength

【讨论】:

    【解决方案2】:

    你已经有了答案,我就一步步写下推导,方便一下子看出来:

    xxf xs = foldr (+) 0 . foldr ((:) . length . flip (:) []) [] $ xs
           = sum         $ foldr ((:) . length . (: []))      []   xs
           = sum         $ foldr (\x -> (:) (length [x]))     []   xs
           = sum         $ foldr (\x r ->    length [x]:r)    []   xs
           = sum         $ map   (\x   ->    length [x]  )         xs
           = sum                            [length [x]  |    x <- xs]  
           = sum                            [ 1          |    x <- xs]
    --     = length xs
    xxf :: (Num n) => [a] -> n
    

    所以,在米兰达,xxf xs = #xs。我猜它的类型是米兰达语法中的:: [*] -&gt; num

    Haskell 的 length:: [a] -&gt; Int,但正如这里定义的那样,它是 :: (Num n) =&gt; [a] -&gt; n,因为它使用了 Num(+) 和两个文字,01

    如果您在可视化 foldr 时遇到问题,那就是

    foldr (+) 0 (a:(b:(c:(d:(e:(...:(z:[])...))))))
          =      a+(b+(c+(d+(e+(...+(z+ 0)...)))))
          = sum [a, b, c, d, e, ..., z]
    

    【讨论】:

      猜你喜欢
      • 2021-03-11
      • 2017-12-04
      • 2017-12-25
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 2011-08-28
      • 1970-01-01
      相关资源
      最近更新 更多