例如,我正在为列表编写一些函数,我想使用长度函数
<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
答案 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
您可以使用相同的想法来编写lengthIsAtLeast
和lengthIsAtMost
变体。
答案 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)
最好以一种他们根本不依赖于输入的有限性或无限性的方式编写你的函数 - 有时它是不可能的,但很多时候它只是重新设计的问题。例如,您可以计算一个运行平均值,而不是计算整个列表的平均值,它本身就是一个列表;如果输入列表是无限的,那么这个列表本身就是无限的,否则就是有限的。
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
绑定在一起低谷了。