Haskell: 在函数内部的 do 块之后使用多个 let 和 return 一个值
Haskell: Using multiple let and return a value after the do block inside a function
正如标题所说,我想 return 在 do 块之后的一个值。
示例:编写一个在数组中的给定位置插入变量的函数:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = do
let before = take n xs
let after = drop n xs
let merged = before ++ [x] ++ after
in merged
例如:
insertAt 'x' 3 "Aleander" => "Alexander"
无论如何,当使用单个 let 调用时,可以 return 使用 in 关键字的值,但是let 的多次调用,如示例所示,我收到错误:
错误:输入“in”时出现解析错误
我知道我可以在一个 let 用法中完成所有事情,但我想知道如何处理多个 let 调用:)
感谢您的帮助!
请不要使用do
表达式。 do
表达式是具有绑定的表达式的语法糖。是的,列表是 Monad
的一个实例,但您没有以正确的方式使用它。
您可以在此处定义您的 let
块,例如:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs =
let before = take n xs
after = drop n xs
merged = before ++ [x] ++ after
in merged
但是使用splitAt :: Int -> [a] -> ([a], [a])
可能更优雅,比如:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = let (hs,ts) = splitAt n xs in hs ++ x : ts
不过,如果你想使用列表 monad,你可以这样写
insertAt x n ys = do
(i, y) <- zip [0..] ys
if i == n then [x, y] else [y]
这取决于 "numbering" 输入列表的每个元素。通常,您只需 return 每个找到的元素(记住,列表 monad 中的 return x == [x]
)。但是在位置n
,你想在现有列表的当前元素之前"sneak in" x
。您可以通过提供列表 [x,y]
而不是简单地 [y]
.
来做到这一点
insertAt 'x' 3 "Aleander"
本质上变成了 concat ["A", "l", "e", "xa", "n", "d", "e", "r"]
.
缺点:它不会将 'x'
附加到输出,无论您提供什么 n
,因此这可能更像是列表 monad 的演示,而不是您实际的解决方案问题。一个简单的修复是针对特殊情况 n == 0
,然后在 n
元素 之后插入 x
。这允许您附加 if n == length ys
,而不是 n > length ys
:
insertAt x n ys = if n == 0 then x:ys else do
(i, y) <- zip [1..] ys -- Note the increase in indices
if i == n then [y, x] else [y]
正如标题所说,我想 return 在 do 块之后的一个值。
示例:编写一个在数组中的给定位置插入变量的函数:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = do
let before = take n xs
let after = drop n xs
let merged = before ++ [x] ++ after
in merged
例如:
insertAt 'x' 3 "Aleander" => "Alexander"
无论如何,当使用单个 let 调用时,可以 return 使用 in 关键字的值,但是let 的多次调用,如示例所示,我收到错误:
错误:输入“in”时出现解析错误
我知道我可以在一个 let 用法中完成所有事情,但我想知道如何处理多个 let 调用:)
感谢您的帮助!
请不要使用do
表达式。 do
表达式是具有绑定的表达式的语法糖。是的,列表是 Monad
的一个实例,但您没有以正确的方式使用它。
您可以在此处定义您的 let
块,例如:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs =
let before = take n xs
after = drop n xs
merged = before ++ [x] ++ after
in merged
但是使用splitAt :: Int -> [a] -> ([a], [a])
可能更优雅,比如:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = let (hs,ts) = splitAt n xs in hs ++ x : ts
不过,如果你想使用列表 monad,你可以这样写
insertAt x n ys = do
(i, y) <- zip [0..] ys
if i == n then [x, y] else [y]
这取决于 "numbering" 输入列表的每个元素。通常,您只需 return 每个找到的元素(记住,列表 monad 中的 return x == [x]
)。但是在位置n
,你想在现有列表的当前元素之前"sneak in" x
。您可以通过提供列表 [x,y]
而不是简单地 [y]
.
insertAt 'x' 3 "Aleander"
本质上变成了 concat ["A", "l", "e", "xa", "n", "d", "e", "r"]
.
缺点:它不会将 'x'
附加到输出,无论您提供什么 n
,因此这可能更像是列表 monad 的演示,而不是您实际的解决方案问题。一个简单的修复是针对特殊情况 n == 0
,然后在 n
元素 之后插入 x
。这允许您附加 if n == length ys
,而不是 n > length ys
:
insertAt x n ys = if n == 0 then x:ys else do
(i, y) <- zip [1..] ys -- Note the increase in indices
if i == n then [y, x] else [y]