【问题标题】:How do I get the list rather than the list element type when using list comprehension?使用列表推导时如何获取列表而不是列表元素类型?
【发布时间】:2018-02-06 01:18:13
【问题描述】:

我在编写一个函数时收到错误,该函数从用户那里获取一个字符串并决定返回 bool 是否是 pangram。由于此错误,我遇到了并发症

“无法将预期类型 Char 与实际类型 [Char] 匹配”。

这是我在 .hs 文件中的所有代码。

lowerlist = ['a'..'z']
upperlist = ['A'.. 'Z']
tlist = zip upperlist lowerlist

pangram s = [if xs == lowerlist then True else False| xs <- lowerlist, xs `elem` s]

如果我将 [] 放在 xs 周围,那么它只会给我一堆“[True, false, true, true, .....]”。

有人可以帮我解决这个问题,或者给我关于这个程序的提示吗?

【问题讨论】:

  • 你能用简单的英语解释一下你的解决方案的假设逻辑吗?
  • @FyodorSoikin s 是取自用户的字符串,xs 是通过匹配 "lowerlist" 和 s 中的字母生成的,然后如果 xs 与 "lowerlist" 中的字母相同,则返回 True for pangram。
  • Nitpick:if &lt;thing&gt; then True else False&lt;thing&gt; 本身相同

标签: haskell list-comprehension


【解决方案1】:

首先,回答您提出的字面问题。在列表推导中引用列表本身的方法是给它一个绑定。人为的例子:

a2z = 'a':[ succ (a2z!!i) | i <- [0..24]]
fibo = 0:1:[fibo !! i + fibo !! (i+1) | i <- [0..]]

现在,至于 pangram 程序。看起来好像您想要自己解决它的提示,而不是一个完整的解决方案,所以:您想要的不是将您的字符串与文字字母表进行比较,而是测试基于输入字符串的谓词是否适用于每个字符字母表。也就是说,您的谓词是输入的某些函数,对于字母表中的all 字符必须为真。你可以试着填补这个骨架上的洞:

import Data.Char (toLower)

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = all (_ ys) alphabet
  where alphabet = ['a'..'z']
        ys = map toLower xs

正如 GHC 会告诉你的,缺失函数的类型是 :: String -&gt; Char -&gt; Bool。所以你也可以这样写:

import Data.Char (toLower)

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = all p alphabet
  where alphabet = ['a'..'z']
        ys = map toLower xs

        p :: Char -> Bool
        p c = _

您可以删除ys 参数并直接在p 中引用ys,因为该变量保存规范化的输入,在p 的范围内。

也许您想对当前程序进行调整。在这种情况下,您生成的列表是Bool 的列表。如果列表包含字母表中的每个字母,则您可以使程序运行,True 如果该字母出现在输入中,False 如果没有。您还可以使用 all 将此列表缩减为单个布尔值。

如果您想要累积字符串中迄今为止遇到的所有字母的集合,并在它等于整个字母表时停止,您需要一个更复杂的递归尾递归函数。它将其累积参数构建为类似于插入Data.List.Ordered,确保仅插入字母表中的元素,每个元素仅插入一次,并在累积集的基数(即有序列表的length ) 与字母表相同。然而,从完整的字母表开始并在遇到元素时删除它们会更有效,当输入或字母表为空时停止:

import Data.Char (toLower)
import Data.List -- You’ll need a function from here.

main :: IO ()
main = interact ( unlines . map show . map isPangram . lines )

isPangram :: String -> Bool
isPangram xs = isPangram' alphabet ys
  where alphabet = ['a'..'z']
        ys = map toLower xs

        isPangram' :: [Char] -> [Char] -> Bool
        isPangram' [] _ = _  -- There are no more letters to search for.
        isPangram' _ [] = _ -- There is nothing left to search.
        isPangram' ws (z:zs) = isPangram' _ _ -- Remove an element from both lists.

另一种方法是将输入 filter 归一化所有无关元素,并将剩下的 nub 作为 Char 的列表。

【讨论】:

    猜你喜欢
    • 2019-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 2018-09-29
    • 2020-05-07
    • 1970-01-01
    • 2014-12-16
    相关资源
    最近更新 更多