Haskell中的多个语句

时间:2009-10-17 01:08:23

标签: haskell syntax

你如何在haskell中有多个语句?

这就是我要做的事情:给定一个像[a,b,c,d]这样的列表,返回其他所有元素,这样你得到[a,c]。我可以看到解决方案,这是我到目前为止所拥有的:

fact (xs)   | length( xs ) `mod` 2  == 1 = head( xs )
    | otherwise = fact(tail( xs ))

这在第一次工作正常,但随后退出。我想说的是返回头部,然后调用fact(tail(xs))我该怎么做?

3 个答案:

答案 0 :(得分:15)

您指定的函数仅返回单个元素。您需要将其更改为:

fact [] = [] -- can't call tail on a list of length 0!
fact (xs)   | length( xs ) `mod` 2  == 1 = head( xs ) : fact(tail(xs))
            | otherwise = fact(tail( xs ))

您可能会发现写出类型签名有助于找出像这样的思想:

fact :: [a] -> [a] -- convert a list of anything to another (shorter) list

然而请注意,这非常慢 - 实际上是O(n ^ 2),因为它在每一步都需要很长时间。更多haskelly解决方案将使用模式匹配来一次处理两个元素:

fact :: [a] -> [a]
-- Take the first element of each two-element pair...
fact (x:_:xs) = x:fact xs
-- If we have only one element left, we had an odd-length list.
-- So grab the last element too.
fact [x]      = [x]
-- Return nothing if we have an empty list
fact _        = []

答案 1 :(得分:14)

Haskell中没有任何陈述。

你不应该滥用Haskell中的括号。相反,你应该习惯自己的语言。所以你原来的代码应该是

fact xs | length xs `mod` 2 == 1 = head xs
        | otherwise              = fact (tail xs)

正如bdonlan所说,你正在寻找的功能真的是

fact []       = []
fact [x]      = [x]
fact (x:_:xs) = x : fact xs

假设我们有列表[a, b, c, d]。让我们应用该函数并完全评估结果。

fact [a, b, c, d] = a : fact [c, d]
                  = a : c : fact []
                  = a : c : []
                  = [a, c]

请注意[a, b, c, d]a : b : c : d : []完全相同,因为编译器可以互换地解释表示列表的两种方式。

答案 2 :(得分:3)

交换信号量

事实上,我们可以遵循两种可能的模式:

  • [1,2,3,4,..]成为[1,3,5,7 ...]
  • [1,2,3,4,..]成为[2,4,6,8 ...]

两者都做同样的事情,但他们以相反的方式“开始计算”。让我们用相同的功能实现它们!当然,必须根据“模式”对该函数进行参数化。存在两种可能的模式,因此,我们需要一个用于参数化的类型的布尔值。实现:让我们使用布尔参数作为“标志”,“信号量”:

module Alternation where

every_second :: [a] -> [a]
every_second =  every_second_at False

every_second_at :: Bool -> [a] -> [a]
every_second_at _ [] = []
every_second_at True  (x : xs) = x : every_second_at False xs
every_second_at False (x : xs) =     every_second_at True xs

我们使用了一个辅助功能,记下“flag / semaphore”:它相应地交换它。实际上,这个辅助功能可以看作是原始任务的概括。我认为,这就是所谓的“worker wrapper”功能。

带索引的倒计时

任务可以进一步推广。为什么不编写更通用的函数,可以通过“modulus m 进行参数化,并“收获”所有 m th 列表中的元素?

  • every_mth 1 [1,2,3,4,...]产生[1,2,3,4 ...]
  • every_mth 2 [1,2,3,4,...]产生[1,3,5 ...]
  • every_mth 3 [1,2,3,4,...]产生[1,4,7 ...]

我们可以使用与以前相同的想法,只需要使用更复杂的“信号量”:自然数而不是布尔值。这是一个“倒计时”参数,一个索引 i 记录在轮到我们时:

module Cycle where

import Nat (Nat)

every_mth :: Nat -> [a] -> [a]
every_mth 0           = undefined
every_mth m @ (i + 1) = every_mth_at m i

我们使用辅助功能(worker wrapper),记录倒计时索引 i

every_mth_at :: Nat -> Nat -> [a] -> [a]
every_mth_at _       _ []       = []
every_mth_at m 0       (x : xs) = x : every_mth m xs
every_nth_at m (i + 1) (x : xs) =     every_mth_at m i xs

为简单起见,自然数字类型在这里被“实现”仅仅是别名:

module Nat (Nat) where

type Nat = Integer

也许,从理论上讲,还有更清晰的替代方法,并不完全等同于你指定的任务,但调整似乎很简单:

  • every_mth 1 [0,1,2,3,4,...]收益[0,1,2,3,4,...]
  • every_mth 2 [0,1,2,3,4,...]收益[0,2,4,6,8...]
  • every_mth 3 [0,1,2,3,4,...]收益[0,3,6,9...]

因此,它在这里指定,以便当应用于所有自然数的惰性列表时,它应该“偶然”提供参数的倍数列表。

在其实施中,值得使用数字作为“从零开始”的索引。我们说:“使用 i 作为0,1,...,的索引,而不是”每个 m th “。 u = m -1,其中 u 表示可能索引的上限。这个上部索引可以是辅助函数中的一个有用参数,下来指数。

module Multiple where

import Nat (Nat)

every_mth :: Nat -> [a] -> [a]
every_mth 0  = undefined
every_mth (u + 1) = countdown u

countdown :: Nat -> [a] -> [a]
countdown = countdown_at 0

countdown_at :: Nat -> Nat -> [a] -> [a]
countdown_at _       _ []       = []
countdown_at 0       u (x : xs) = x : countdown_at u u xs
countdown_at (i + 1) u (x : xs) =     countdown_at i u xs