如何实现一个函数来更改数组单元格以避免 haskell 中的非详尽模式错误?
How to implement a function to change array cells avoiding non-exhaustive pattern errors in haskell?
我的目标是编写一个名为 walk 的函数,它可以切换迷宫单元与其相邻单元的值。
例如调用 walk 0 labyrinthA 应该将 T 向左移动一个单元格。Here i tried to change a value of a labyrinth cell in ghci.
showLabyrinth labyrinth =
putStrLn $ unlines $ [[labyrinth j i | i <- [1..dimH]] | j <- [1..dimV]]
where
dimH = length . takeWhile (/='O') $ [labyrinth 1 i | i <- [1..]]
dimV = length . takeWhile (/='O') $ [labyrinth i 1 | i <- [1..]]
labyrinthA 9 _ = 'O'
labyrinthA _ 16 = 'X'
labyrinthA _ 17 = 'O'
labyrinthA 1 _ = 'X'
labyrinthA 2 1 = 'X'
labyrinthA 2 8 = 'X'
labyrinthA 2 12 = 'X'
labyrinthA 2 _ = ' '
labyrinthA 3 1 = 'X'
labyrinthA 3 3 = 'X'
labyrinthA 3 5 = 'X'
labyrinthA 3 6 = 'X'
labyrinthA 3 8 = 'X'
labyrinthA 3 9 = 'X'
labyrinthA 3 10 = 'X'
labyrinthA 3 12 = 'X'
labyrinthA 3 14 = 'M'
labyrinthA 3 _ = ' '
labyrinthA 4 1 = 'X'
labyrinthA 4 2 = 'X'
labyrinthA 4 3 = 'X'
labyrinthA 4 5 = 'X'
labyrinthA 4 6 = 'X'
labyrinthA 4 12 = 'X'
labyrinthA 4 _ = ' '
labyrinthA 5 1 = 'X'
labyrinthA 5 5 = 'X'
labyrinthA 5 8 = 'X'
labyrinthA 5 9 = 'X'
labyrinthA 5 10 = 'X'
labyrinthA 5 12 = 'X'
labyrinthA 5 13 = 'X'
labyrinthA 5 15 = 'X'
labyrinthA 5 _ = ' '
labyrinthA 6 1 = 'X'
labyrinthA 6 3 = 'X'
labyrinthA 6 4 = 'X'
labyrinthA 6 5 = 'X'
labyrinthA 6 7 = 'X'
labyrinthA 6 8 = 'X'
labyrinthA 6 10 = 'X'
labyrinthA 6 _ = ' '
labyrinthA 7 1 = 'X'
labyrinthA 7 6 = 'T'
labyrinthA 7 9 = 'X'
labyrinthA 7 10 = 'X'
labyrinthA 7 11 = 'X'
labyrinthA 7 12 = 'X'
labyrinthA 7 13 = 'X'
labyrinthA 7 14 = 'X'
labyrinthA 7 15 = 'X'
labyrinthA 7 _ = ' '
labyrinthA 8 6 = 'E'
labyrinthA 8 _ = 'X'
现在我试着让 'T' 向左走 walk 0 labyrinthA
walk direction labyrinth | direction == 0 = let labyrinth (yKoord 'T')
(xKoord 'T') = ' ' && let labyrinth (yKoord) ((xKoord+1)) = 'T'
| direction == 1 = undefined
| direction == 2 = undefined
| direction == 3 = undefined
其中 yKoord 和 xKoord 是整数。
enter image description here
您遇到的错误是因为模式并未涵盖所有情况。 穷举 模式是穷尽所有可能性的模式,即 returns 每个潜在输入值的结果。
在这里,如果您调用 labyrinthA 10 1
会发生什么情况?还是labyrinthA 0 0
?如果您的编译器没有在编译时就此错误向您发出警告,您可能需要使用 -Wall
标志进行编译以打开警告。
如果程序逻辑使得无法使用任何其他值调用该函数(在这种情况下,它可能应该是一个只能从一个地方调用的本地函数),有一个快速修复方法。在函数底部添加这样一行:
labyrinthA x y = error $ "Domain error: labyrinthA " ++ show x ++
" " ++ show y
这添加了一个包罗万象的子句,匹配任何尚未涵盖的模式,满足编译器的要求。如果函数确实以“不可能”的值被调用,逻辑错误现在将使程序崩溃,并显示一条信息更丰富的调试消息。
在您的情况下,您未向我们展示的程序的其他部分使用其域外的值调用您的函数,这会导致运行时崩溃。不幸的是,我们无法在无法查看代码的情况下为您提供帮助,但追踪导致崩溃的调用顺序将是很好的第一步。
在这个特定实例中,您可能不希望玩家每次迈出一步时都更新迷宫地图。在函数式语言中,这不是一个非常有效或优雅的操作。相反,您可以存储不可变地图,然后更新播放器的位置,以在其上绘制。 (X,Y) 坐标可以是您传递的另一个参数或程序状态数据的一部分。
这没有回答您关于在定义函数后修改函数的问题。我认为这是一个 XY 问题,但这是对这部分问题的字面答案。您不能使用 String
类型执行此操作。有一些方法可以在 Haskell 中获取可变状态,例如具有 ST
类型的可变 Data.Vector.MVector
,但这不是您的直接问题。
我的目标是编写一个名为 walk 的函数,它可以切换迷宫单元与其相邻单元的值。 例如调用 walk 0 labyrinthA 应该将 T 向左移动一个单元格。Here i tried to change a value of a labyrinth cell in ghci.
showLabyrinth labyrinth =
putStrLn $ unlines $ [[labyrinth j i | i <- [1..dimH]] | j <- [1..dimV]]
where
dimH = length . takeWhile (/='O') $ [labyrinth 1 i | i <- [1..]]
dimV = length . takeWhile (/='O') $ [labyrinth i 1 | i <- [1..]]
labyrinthA 9 _ = 'O'
labyrinthA _ 16 = 'X'
labyrinthA _ 17 = 'O'
labyrinthA 1 _ = 'X'
labyrinthA 2 1 = 'X'
labyrinthA 2 8 = 'X'
labyrinthA 2 12 = 'X'
labyrinthA 2 _ = ' '
labyrinthA 3 1 = 'X'
labyrinthA 3 3 = 'X'
labyrinthA 3 5 = 'X'
labyrinthA 3 6 = 'X'
labyrinthA 3 8 = 'X'
labyrinthA 3 9 = 'X'
labyrinthA 3 10 = 'X'
labyrinthA 3 12 = 'X'
labyrinthA 3 14 = 'M'
labyrinthA 3 _ = ' '
labyrinthA 4 1 = 'X'
labyrinthA 4 2 = 'X'
labyrinthA 4 3 = 'X'
labyrinthA 4 5 = 'X'
labyrinthA 4 6 = 'X'
labyrinthA 4 12 = 'X'
labyrinthA 4 _ = ' '
labyrinthA 5 1 = 'X'
labyrinthA 5 5 = 'X'
labyrinthA 5 8 = 'X'
labyrinthA 5 9 = 'X'
labyrinthA 5 10 = 'X'
labyrinthA 5 12 = 'X'
labyrinthA 5 13 = 'X'
labyrinthA 5 15 = 'X'
labyrinthA 5 _ = ' '
labyrinthA 6 1 = 'X'
labyrinthA 6 3 = 'X'
labyrinthA 6 4 = 'X'
labyrinthA 6 5 = 'X'
labyrinthA 6 7 = 'X'
labyrinthA 6 8 = 'X'
labyrinthA 6 10 = 'X'
labyrinthA 6 _ = ' '
labyrinthA 7 1 = 'X'
labyrinthA 7 6 = 'T'
labyrinthA 7 9 = 'X'
labyrinthA 7 10 = 'X'
labyrinthA 7 11 = 'X'
labyrinthA 7 12 = 'X'
labyrinthA 7 13 = 'X'
labyrinthA 7 14 = 'X'
labyrinthA 7 15 = 'X'
labyrinthA 7 _ = ' '
labyrinthA 8 6 = 'E'
labyrinthA 8 _ = 'X'
现在我试着让 'T' 向左走 walk 0 labyrinthA
walk direction labyrinth | direction == 0 = let labyrinth (yKoord 'T')
(xKoord 'T') = ' ' && let labyrinth (yKoord) ((xKoord+1)) = 'T'
| direction == 1 = undefined
| direction == 2 = undefined
| direction == 3 = undefined
其中 yKoord 和 xKoord 是整数。
enter image description here
您遇到的错误是因为模式并未涵盖所有情况。 穷举 模式是穷尽所有可能性的模式,即 returns 每个潜在输入值的结果。
在这里,如果您调用 labyrinthA 10 1
会发生什么情况?还是labyrinthA 0 0
?如果您的编译器没有在编译时就此错误向您发出警告,您可能需要使用 -Wall
标志进行编译以打开警告。
如果程序逻辑使得无法使用任何其他值调用该函数(在这种情况下,它可能应该是一个只能从一个地方调用的本地函数),有一个快速修复方法。在函数底部添加这样一行:
labyrinthA x y = error $ "Domain error: labyrinthA " ++ show x ++
" " ++ show y
这添加了一个包罗万象的子句,匹配任何尚未涵盖的模式,满足编译器的要求。如果函数确实以“不可能”的值被调用,逻辑错误现在将使程序崩溃,并显示一条信息更丰富的调试消息。
在您的情况下,您未向我们展示的程序的其他部分使用其域外的值调用您的函数,这会导致运行时崩溃。不幸的是,我们无法在无法查看代码的情况下为您提供帮助,但追踪导致崩溃的调用顺序将是很好的第一步。
在这个特定实例中,您可能不希望玩家每次迈出一步时都更新迷宫地图。在函数式语言中,这不是一个非常有效或优雅的操作。相反,您可以存储不可变地图,然后更新播放器的位置,以在其上绘制。 (X,Y) 坐标可以是您传递的另一个参数或程序状态数据的一部分。
这没有回答您关于在定义函数后修改函数的问题。我认为这是一个 XY 问题,但这是对这部分问题的字面答案。您不能使用 String
类型执行此操作。有一些方法可以在 Haskell 中获取可变状态,例如具有 ST
类型的可变 Data.Vector.MVector
,但这不是您的直接问题。