Haskell的跨度函数
Haskell's span function
我对 Haskell 比较陌生,我正在努力寻找一种方法来实现 Haskell 的 span
功能。但是,我的问题比那个更普遍,因为我不知道如何使函数 return 成为包含我想要的元素的列表列表或元组列表。我的列表列表问题,例如:
[[1],[2]]
是我无法让函数将元素添加到列表列表中的第一个列表。我只知道如何将另一个列表附加到列表列表中。
简而言之,如果您向我解释如何实现 span
功能,我应该会清楚这一切。
所以我认为你所说的是你知道如何通过做类似
的事情递归地附加到列表
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)
请注意,这会强制函数不惰性。
我认为您要在此处使用的一般模式如下:
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
条件中的模式匹配。这意味着我们是:
- 调用
span pred xs
,生成一对列表;
- 这对的模式匹配;
- 分别命名对的第一个和第二个元素
prefix'
和 suffix'
。
我怀疑第 2 步,即递归调用结果的模式匹配,您可能没有理解。
第二个不明显的事情是递归。这是一件棘手的事情,因为,与直觉相反,要用递归解决问题,您需要假设您已经解决了它,但是对于 "wrong" 论点——如果您还没有解决,想象自己采取的艰难步骤还没完成!但诀窍是:
- 假设您实际上已经解决了问题,但是对于列表的 tail。这就是
prefix'
和 suffix'
变量包含的内容:一个正确的解决方案,但对于错误的列表——您实际要解决的那个的尾部。
- 鉴于该(非)解决方案,您如何重新使用它来为您的问题找到正确的解决方案?
我对 Haskell 比较陌生,我正在努力寻找一种方法来实现 Haskell 的 span
功能。但是,我的问题比那个更普遍,因为我不知道如何使函数 return 成为包含我想要的元素的列表列表或元组列表。我的列表列表问题,例如:
[[1],[2]]
是我无法让函数将元素添加到列表列表中的第一个列表。我只知道如何将另一个列表附加到列表列表中。
简而言之,如果您向我解释如何实现 span
功能,我应该会清楚这一切。
所以我认为你所说的是你知道如何通过做类似
的事情递归地附加到列表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)
请注意,这会强制函数不惰性。
我认为您要在此处使用的一般模式如下:
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
条件中的模式匹配。这意味着我们是:
- 调用
span pred xs
,生成一对列表; - 这对的模式匹配;
- 分别命名对的第一个和第二个元素
prefix'
和suffix'
。
我怀疑第 2 步,即递归调用结果的模式匹配,您可能没有理解。
第二个不明显的事情是递归。这是一件棘手的事情,因为,与直觉相反,要用递归解决问题,您需要假设您已经解决了它,但是对于 "wrong" 论点——如果您还没有解决,想象自己采取的艰难步骤还没完成!但诀窍是:
- 假设您实际上已经解决了问题,但是对于列表的 tail。这就是
prefix'
和suffix'
变量包含的内容:一个正确的解决方案,但对于错误的列表——您实际要解决的那个的尾部。 - 鉴于该(非)解决方案,您如何重新使用它来为您的问题找到正确的解决方案?