在 Haskell 中执行 where 子句
Execution of where clause in Haskell
我得到了以下我知道有效的代码片段,但我对Haskell完全陌生,并且有 2 个关于 where 子句的问题。
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status --- Base Case
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status --- Case 1
| status !! (p2-1) == 1 = f3 tail newStatus1 --- Case 2
| otherwise = f3 tail newStatus2 --- Case 3
where newStatus1 = set status p1 0 --- Line 7
newStatus2 = set newStatus2Temp p1 1 --- Line 8
newStatus2Temp = set status p2 0 --- Line 9
所以基本上 f3 谓词有 2 个参数:
- 整数列表的列表,如下所示:[[1,2],[2,3],[3,2]]
- 一个整数列表
它的输出是最后更新的第二个参数。
如您所见,除了基本情况外,我还有 2 个情况 (2) 和 (3),其中 status/[Int] 参数通过 标准集合谓词 .
问题 1) :
- 假设情况 2 成立。 Haskell 是否执行第 8 行和第 9 行?
- 假设情况 3 成立。 Haskell 是否执行第 7 行?
问题 2) :
- 守卫能有自己的位置吗?
- 有没有更好的方法来实际做到这一点?
作为惰性求值的结果,如果在对匹配的情况。所以:
- 如果情况 1 成立,第 7-9 行的 none 是 运行。
- 如果情况 1 为假但情况 2 为真,则评估
newStatus
运行 的第 7 行,但第 8-9 行不是 运行.
- 如果情况 1 和情况 2 为假但情况 3 为真,则对
newStatus2
运行 的第 8 行求值 newStatus2Temp
导致第 9 行变为 运行 .第 7 行不是 运行.
where
子句本身只能附加到整个模式绑定(例如,整个 f3 ([p1,p2]:tail) status | ... | ... = ...
表达式),而不是单个守卫,因此守卫不能有自己的 where
子句。您可以为每个守卫重复该模式:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status | status !! (p1-1) == 0 = f3 tail status
f3 ([p1,p2]:tail) status | status !! (p2-1) == 1 = f3 tail newStatus1
where newStatus1 = set status p1 0
f3 ([p1,p2]:tail) status | otherwise = f3 tail newStatus2
where newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
或使用let ... in ...
块:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status
| status !! (p2-1) == 1
= let newStatus1 = set status p1 0
in f3 tail newStatus1
| otherwise
= let newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
in f3 tail newStatus2
我认为您的 where
子句版本没有任何问题,并且编写 Haskell 代码的情况并不少见,其中只有 where
中绑定的子集每种情况都使用 -clause(甚至 valid/meaningful)。有了这么小的助手,这个具体的例子可能会在没有任何助手的情况下写得更清楚:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail $ status
| status !! (p2-1) == 1 = f3 tail $ set status p1 0
| otherwise = f3 tail $ set (set status p2 0) p1 1
使用 GHC 和 -O2
,所有这四种(您的原始代码和这三种变体)都可以编译为相同的低级代码,因此请使用您认为最清楚的一种。
我得到了以下我知道有效的代码片段,但我对Haskell完全陌生,并且有 2 个关于 where 子句的问题。
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status --- Base Case
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status --- Case 1
| status !! (p2-1) == 1 = f3 tail newStatus1 --- Case 2
| otherwise = f3 tail newStatus2 --- Case 3
where newStatus1 = set status p1 0 --- Line 7
newStatus2 = set newStatus2Temp p1 1 --- Line 8
newStatus2Temp = set status p2 0 --- Line 9
所以基本上 f3 谓词有 2 个参数:
- 整数列表的列表,如下所示:[[1,2],[2,3],[3,2]]
- 一个整数列表
它的输出是最后更新的第二个参数。
如您所见,除了基本情况外,我还有 2 个情况 (2) 和 (3),其中 status/[Int] 参数通过 标准集合谓词 .
问题 1) :
- 假设情况 2 成立。 Haskell 是否执行第 8 行和第 9 行?
- 假设情况 3 成立。 Haskell 是否执行第 7 行?
问题 2) :
- 守卫能有自己的位置吗?
- 有没有更好的方法来实际做到这一点?
作为惰性求值的结果,如果在对匹配的情况。所以:
- 如果情况 1 成立,第 7-9 行的 none 是 运行。
- 如果情况 1 为假但情况 2 为真,则评估
newStatus
运行 的第 7 行,但第 8-9 行不是 运行. - 如果情况 1 和情况 2 为假但情况 3 为真,则对
newStatus2
运行 的第 8 行求值newStatus2Temp
导致第 9 行变为 运行 .第 7 行不是 运行.
where
子句本身只能附加到整个模式绑定(例如,整个 f3 ([p1,p2]:tail) status | ... | ... = ...
表达式),而不是单个守卫,因此守卫不能有自己的 where
子句。您可以为每个守卫重复该模式:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status | status !! (p1-1) == 0 = f3 tail status
f3 ([p1,p2]:tail) status | status !! (p2-1) == 1 = f3 tail newStatus1
where newStatus1 = set status p1 0
f3 ([p1,p2]:tail) status | otherwise = f3 tail newStatus2
where newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
或使用let ... in ...
块:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail status
| status !! (p2-1) == 1
= let newStatus1 = set status p1 0
in f3 tail newStatus1
| otherwise
= let newStatus2 = set newStatus2Temp p1 1
newStatus2Temp = set status p2 0
in f3 tail newStatus2
我认为您的 where
子句版本没有任何问题,并且编写 Haskell 代码的情况并不少见,其中只有 where
中绑定的子集每种情况都使用 -clause(甚至 valid/meaningful)。有了这么小的助手,这个具体的例子可能会在没有任何助手的情况下写得更清楚:
f3 :: [[Int]] -> [Int] -> [Int]
f3 [] status = status
f3 ([p1,p2]:tail) status
| status !! (p1-1) == 0 = f3 tail $ status
| status !! (p2-1) == 1 = f3 tail $ set status p1 0
| otherwise = f3 tail $ set (set status p2 0) p1 1
使用 GHC 和 -O2
,所有这四种(您的原始代码和这三种变体)都可以编译为相同的低级代码,因此请使用您认为最清楚的一种。