对不起标题血腥(如果你能建议更好,请做)。但我的问题是,我不太明白如何让这个块工作。我有一个代码,可以在列表列表中返回5
的位置。像这样:
findFive :: [[Int]] -> (Int, Int)
findFive rs = do
x <- xPos rs 0
y <- yPos rs 0
return ( (x,y) )
xPos :: [[Int]] -> Int -> Int
xPos (rs:[[]]) n = n
xPos (rs:rss) n | elem 5 rs = n
| otherwise = xPos rss (n+1)
yPos :: [[Int]] -> Int -> Int
yPos (rs:[[]]) n = n
yPos (rs:rss) n | elem 5 rs = n
| otherwise = yPos rss (n+1)
我
但我不能用这种方式阻止我。我可以通过
来实现它findFive :: [[Int]] -> (Int, Int)
findFive xs = ( (xPos xs 0), (yPos (transpose (xs)) 0) )
但这看起来有点难看。
此外,有没有办法让这个工作无需发送到0
xPos
和yPos
?
答案 0 :(得分:8)
为什么do
?那里没有单子。 let..in
足够了:
findFive :: [[Int]] -> (Int, Int)
findFive rs = let
x = xPos rs 0
y = yPos rs 0
in (x,y)
或者,使用where
:
findFive :: [[Int]] -> (Int, Int)
findFive rs = (x, y)
where
x = xPos rs 0
y = yPos rs 0
答案 1 :(得分:0)
您不能以这种方式使用do
块,因为在do
块中您必须(1)将名称绑定到&#39;内容&#39; monadic值,和(2)返回包含在(1)中使用的相同monadic类型的值。在这种情况下,monadic类型将是列表。返回(行,列)对的列表是合适的,因为它会自动处理未找到数字或多次查找的情况。所以我们可以做类似
import Control.Monad
findFive ::
[[Int]] -> -- ^ a matrix of numbers.
[(Int, Int)] -- ^ the (zero-indexed) rows and columns of the number
-- ^ @5@, if any (otherwise empty list).
findFive xss =
do
(xs, rowIdx) <- xss `zip` [0 ..]
(x, colIdx) <- xs `zip` [0 ..]
guard $ x == 5
return (rowIdx, colIdx)
input :: [[Int]]
input = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
-- Should print "row: 1, col: 1".
main :: IO ()
main =
forM_ (findFive input) $ \(rowIdx, colIdx) ->
do
putStr "row: "
putStr $ show rowIdx
putStr ", col: "
print colIdx
答案 2 :(得分:0)
假设pos
以这种方式定义:
pos :: Eq => a -- A value to find
-> [[a]] -- A 2d matrix
-> Maybe Int -- Index of first row containing the value, if any
pos k rows = pos' rows 0
where pos' [] _ = Nothing
pos' (x:xs) n | elem k x = n
| otherwise = pos' xs (n+1)
这里有一些变化:
Int
。k :: a
,而不只是5。k
的任何行。通过这个定义,我们可以将findFive
定义为
findFive :: [[Int]] -> (Maybe Int, Maybe Int)
findFive xs = (pos 5 xs, pos 5 (transpose xs))
使用Control.Lens
,您可以将函数pos 5
分解出来,这样它只需要写一次。将over both
视为map
的版本,而不是列表。
import Control.Lens
findFive xs = over both (pos 5) (xs, transpose xs)
使用Control.Arrow
,您可以将参数xs
分解出去,这样 it 只需要写一次。
import Control.Lens
import Control.Arrow
findFive xs = over both (pos 5) ((id &&& transpose) xs)
-- id &&& transpose = \x -> (id x, transpose x)
完成后,您可以通过撰写findFive
和over both (pos 5)
轻松编写id &&& transpose
无点样式:
findFive = over both (pos 5) . (id &&& transpose)