当前位置: 首页 > 知识库问答 >
问题:

哈斯克尔跨度函数

余铭晨
2023-03-14

我对Haskell比较陌生,我正在努力找到一种实现Haskell的span函数的方法。然而,我的问题比这更一般,因为我不知道如何使函数返回包含所需元素的列表或元组列表。我对列表的问题,例如:

[[1],[2]]

是我不能让函数在列表列表中的第一个列表中添加一个元素。我只知道如何将另一个列表附加到列表列表中。

简而言之,如果您向我解释如何实现span函数,我希望这一切都会清楚。

共有2个答案

易昌翰
2023-03-14

我认为您在这里要使用的一般模式如下:

span :: (a -> Bool) -> [a] -> ([a], [a])
span pred [] = ([], [])
span pred (x:xs) = if pred x then _ else _  -- fill in the blanks
    where (prefix', suffix') = span pred xs

那里有两件不明显的事情。首先,注意where条件中的模式匹配。这意味着我们是:

  1. 调用transpred xs,这会产生一对列表;
  2. 这对上的模式匹配;
  3. 分别命名对前缀'后缀'的第一个和第二个元素。

我怀疑步骤#2,递归调用结果的模式匹配,是您可能不理解的。

第二件不明显的事情是递归。这是一件棘手的事情,因为与直觉相反,要用递归解决一个问题,你需要假设你已经解决了它,但对于“错误”的论点——如果你还没有解决它,那么想象一下你自己正在采取的一个艰难的步骤!但诀窍在于:

  • 想象一下,你实际上已经解决了这个问题,但在列表的末尾。这就是前缀和后缀变量所包含的内容:一个正确的解决方案,但适用于错误的列表——您实际试图求解的列表的尾部
禄仲渊
2023-03-14

所以我想你说的是,你知道如何通过如下操作递归地附加到列表中

foobar :: [x] -> [y]
foobar (  []) = []
foobar (x:xs) = {- ...stuff... -} : foobar xs

但您不知道如何使用两个列表来实现这一点:

foobar :: [x] -> ([y], [z])
foobar (x:xs) = ???

一般来说,当结果不是列表,而是包含列表的东西时,您最终会执行如下操作:

foobar :: [x] -> ([y], [z])
foobar (x:xs) =
  let
    y = {- whatever -}
    z = {- whatever -}
    (ys, zs) = foobar xs   -- The recursive call
  in  (y:ys, z:zs)

这同样适用于,比如说,结果是一个一元动作

foobar :: [x] -> IO [y]
foobar (x:xs) = do
  y  <- {- whatever -}
  ys <- foobar xs
  return (y:ys)

请注意,这会强制函数不懒惰。

 类似资料:
  • :101:22:ERROR:•在表达式“count words”的第一个参数中的“hello”中,即表达式:countWords[“hello”,“hello”,“world”]中的“[”hello“,”hello“,”world“]”中,无法将预期类型“Char”与实际类型“[Char]”匹配• :101:31:error:•在表达式“count words”的第一个参数中的“world”中,即

  • 我正在尝试在 Haskell 中实现一个函数,该函数返回一个列表,其中包含玩家的所有可能动作。该函数的唯一参数是一个字符串,由棋盘的实际状态(在福赛斯-爱德华兹符号中)组成,后跟移动的玩家(b/w)。 符号示例:rnbqkbnr/pppppp/8/8/8/PPPPPPP/rnbqkbnr w(起始板状态) 移动以[origin]-[destination]格式的字符串传输。目的地始终是形式[col

  • 我已经开始学习Haskell,我读到Haskell中的每一个函数只需要一个参数,我不明白在Haskell的庇护下发生了什么魔法,这使得它成为可能,我想知道它是否有效。 上面的签名意味着函数接受一个,然后返回另一个函数,该函数接受一个,并返回一个 示例1相对简单,但我开始想知道当函数稍微复杂一点时会发生什么。 在这个例子中,我编写了一个函数,并以两种方式执行它,一次传递一个参数,一次传递所有参数。

  • Haskell(使用编译器)比您预期的要快得多。如果使用得当,它可以接近低级语言。(Haskellers最喜欢做的一件事是尝试将C语言的5%以内(甚至超过它,但这意味着您使用的是一个低效的C程序,因为GHC将Haskell编译为C)。)我的问题是,为什么?

  • Scala开发人员学习IO单元体,因此一般的蹦床技术对于不可能进行尾调用优化的递归是必要的,我想知道Haskell是如何避免它的。 我知道Haskell是一种懒惰的语言,但是我想知道是否有人可以再详细说明一下。 例如,为什么ForeverM stackoverflow不在Scala中运行?好吧,我可以回答蹦床,我可以找到实际的代码,在图书馆和博客。我自己居然实现了一个基本的蹦床来学习。 在哈斯克尔

  • GHC能否简化id=(\(a,b)- 更复杂的情况呢: GHC将简化映射到映射中? 我试图使用简单的beta缩减,但由于糟糕的模式匹配,这些术语看起来是不可缩减的。 因此,我很好奇GHC的优化技术如何处理这个问题。