2017-06-12 44 views
0

我想在Haskell中解决以下问题:给定一个整数返回其数字列表。约束是我只能使用fold *函数中的一个(* = {r,l,1,l1})。使用fold *在Haskell中增长列表

没有这样的约束,那么代码很简单:

list_digits :: Int -> [Int] 
list_digits 0 = [] 
list_digits n = list_digits r ++ [n-10*r] 
       where 
        r = div n 10 

可是我怎么用倍*来,基本上是从一个空表增长的数字的名单?

在此先感谢。

+2

你确定你不能使用'unfoldr'吗?还是别的什么?所有的折叠功能需要一些列表(或“折叠”)作为输入折叠... – Alec

+0

亚历克,我不熟悉展开*。我认为可能,这是要走的路(以及问题要求的实际含义)。谢谢。 –

+2

你可以用'list_digits = unfoldr(\ i - > if if == 0 then Nothing else let(q,r)= quotRem i 10在Just(r,q))''中很容易地获得数字。 – Alec

回答

1

这是一个家庭作业吗?分配要求您使用foldr是非常奇怪的,因为这是unfoldr的自然使用,而不是foldrunfoldr :: (b -> Maybe (a, b)) -> b -> [a]构建列表,而foldr :: (a -> b -> b) -> b -> [a] -> b消耗列表。使用foldr的这个函数的实现将被可怕地扭曲。

listDigits :: Int -> [Int] 
listDigits = unfoldr digRem 
    where digRem x 
       | x <= 0 = Nothing 
       | otherwise = Just (x `mod` 10, x `div` 10) 

在命令式编程语言,这基本上是一个while循环。循环的每次迭代将x `mod` 10附加到输出列表并将x `div` 10传递给下一次迭代。在,比方说,Python和this'd写成

def list_digits(x): 
    output = [] 
    while x > 0: 
     output.append(x % 10) 
     x = x // 10 
    return output 

unfoldr使我们能够在一个更高的层次表达的循环。 unfoldr捕捉“一次构建一个项目列表”的模式,并使其明确。您不必考虑循环的顺序行为,并意识到列表正在一次构建一个元素,就像您使用Python代码一样;你只需要知道unfoldr是做什么的。诚然,用折叠和展开进行编程需要一点时间才能习惯,但为了更好的表现力,这是值得的。

如果您分配由机器标记,它确实需要你的话foldr输入到你的程序的文字,(你应该问你的老师他们为什么这样做和)你可以玩偷偷摸摸的伎俩有以下“id[] -as- foldr“功能:

obfuscatedId = foldr (:) [] 
listDigits = obfuscatedId . unfoldr digRem 
0

虽然unfoldr大概是什么意思任务,你可以,如果你使用foldr作为hylomorphism,那就是建立一个列表,而它的另一个泪写这使用foldr下。

digits :: Int -> [Int] 
digits n = snd $ foldr go (n, []) places where 
    places = replicate num_digits() 
    num_digits | n > 0  = 1 + floor (logBase 10 $ fromIntegral n) 
      | otherwise = 0 
    go() (n, ds) = let (q,r) = n `quotRem` 10 in (q, r : ds) 

实际上,我们在这里所做的是使用foldr“地图,用状态”。我们知道提前 需要输出多少位数(使用log10)而不是那些数字是什么,所以我们使用 单位(())值作为这些数字的替代值。

如果你的老师只是有foldr在顶层一个坚持己见的人,你可以得到 逃脱使go部分:

digits' :: Int -> [Int] 
digits' n = foldr go [n] places where 
    places = replicate num_digits() 
    num_digits | n > 0  = floor (logBase 10 $ fromIntegral n) 
      | otherwise = 0 
    go() (n:ds) = let (q,r) = n `quotRem` 10 in (q:r:ds) 

这对非正数稍有不同的行为:

>>> digits 1234567890 
[1,2,3,4,5,6,7,8,9,0] 
>>> digits' 1234567890 
[1,2,3,4,5,6,7,8,9,0] 
>>> digits 0 
[] 
>>> digits' 0 
[0] 
>>> digits (negate 1234567890) 
[] 
>>> digits' (negate 1234567890) 
[-1234567890]