有没有办法分离无限和有限列表?

时间:2015-10-08 12:52:43

标签: list haskell infinite

例如,我正在为列表编写一些函数,我想使用长度函数

<input type="hidden" name="peopleName" value="<?php echo $a['name']?>">

如果有人理解这个功能是否可以与无限列表一起使用?

或者我应该总是考虑无限列表并使用类似的东西

foo :: [a] -> Bool
foo xs = length xs == 100

而不是直接使用长度?

如果haskell具有FiniteList类型,那么长度和foo将是

foo :: [a] -> Bool
foo xs = length (take 101 xs) == 100

5 个答案:

答案 0 :(得分:9)

length遍历整个列表,但要确定列表是否具有特定长度n,您只需要查看第一个n元素。

您使用take的想法会奏效。另外 你可以像这样写一个lengthIs函数:

-- assume n >= 0
lengthIs 0 [] = True
lengthIs 0 _  = False
lengthIs n [] = False
lengthIs n (x:xs) = lengthIs (n-1) xs

您可以使用相同的想法来编写lengthIsAtLeastlengthIsAtMost变体。

答案 1 :(得分:5)

编辑时:我主要回答你标题中的问题,而不是你特定例子的具体细节(ErikR的回答非常好)。

列表上的许多函数(例如length本身)仅对有限列表有意义。如果您正在编写的函数仅对有限列表有意义,请在文档中明确说明(如果它不明显)。由于暂停问题无法解决,因此无法执行限制。根本没有算法提前确定是否理解

takeWhile f [1..]

(其中f是整数的谓词)产生有限或无限列表。

答案 2 :(得分:4)

Nat和懒惰再次袭击:

import Data.List

data Nat = S Nat | Z deriving (Eq)

instance Num Nat where
    fromInteger 0 = Z
    fromInteger n = S (fromInteger (n - 1))

    Z   + m = m
    S n + m = S (n + m)

lazyLength :: [a] -> Nat
lazyLength = genericLength

main = do
    print $ lazyLength [1..]    == 100 -- False
    print $ lazyLength [1..100] == 100 -- True

答案 3 :(得分:2)

ErikR和John Coleman已经回答了你问题的主要部分,但是我想指出一些事情:

最好以一种他们根本不依赖于输入的有限性或无限性的方式编写你的函数 - 有时它是不可能的,但很多时候它只是重新设计的问题。例如,您可以计算一个运行平均值,而不是计算整个列表的平均值,它本身就是一个列表;如果输入列表是无限的,那么这个列表本身就是无限的,否则就是有限的。

avg :: [Double] -> [Double]
avg = drop 1 . scanl f 0.0 . zip [0..]
  where f avg (n, i) = avg * (dbl n / dbl n') +
                       i            / dbl n'      where n'  = n+1
                                                        dbl = fromInteger

在这种情况下,您可以平均无限列表,而不必采用其length

*Main> take 10 $ avg [1..]
[1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0]

换句话说,一个选项是设计尽可能多的函数,而不是关心无穷大方面,并将列表和其他(可能是无限的)数据结构的(完全)评估延迟到阶段的后期在您的计划中尽可能。

通过这种方式,它们也将更具可重用性和可组合性 - 任何对其输入具有更少或更多一般假设的东西往往更具可组合性;相反,任何具有更多或更具体假设的东西往往不太可组合,因此不太可重复使用。

答案 4 :(得分:1)

制作有限列表类型有几种不同的方法。第一个是简单地使列表严格:

data FList a = Nil | Cons a !(FList a)

不幸的是,这会使懒惰带来所有效率上的好处。其中一些可以通过使用长度索引列表来恢复:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}

data Nat = Z | S Nat deriving (Show, Read, Eq, Ord)

data Vec :: Nat -> * -> * where
  Nil :: Vec 'Z a
  Cons :: a -> Vec n a -> Vec ('S n) a

instance Functor (Vec n) where
  fmap _f Nil = Nil
  fmap f (Cons x xs) = Cons (f x) (fmap f xs)

data FList :: * -> * where
  FList :: Vec n a -> FList a

instance Functor FList where
  fmap f (FList xs) = FList (fmap f xs)

fcons :: a -> FList a -> FList a
fcons x (FList xs) = FList (Cons x xs)

funcons :: FList a -> Maybe (a, FList a)
funcons (FList Nil) = Nothing
funcons (FList (Cons x xs)) = Just (x, FList xs)

-- Foldable and Traversable instances are straightforward
-- as well, and in recent GHC versions, Foldable brings
-- along a definition of length.

GHC不允许无限类型,因此无法构建无限Vec,因此无法构建无限FList(1)。但是,FList可以稍微懒惰地转换和消耗,具有缓存和垃圾收集的好处。

(1)请注意,类型系统强制fcons在其FList参数中严格,因此任何尝试将结FList绑定在一起低谷了。