Я получил следующий фрагмент кода, который, как я знаю, работает, но я совершенно не знаком с 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 аргумента:
Его вывод является последним обновленным вторым аргументом.
Как вы видите, помимо базового случая, у меня есть 2 случая (2) и (3), где аргумент status/[Int] через стандартный набор предикатов.
Вопрос 1) :
Вопрос 2) :
@WillemVanOnsem Настоящим домашним заданием было «перевести» предикат f3 из Prolog в Haskell. Я придумал именно такой способ, и мне было интересно, не экономит ли то, как я это делаю, или что-то в этом роде. Кстати, мне нужно нести аргумент состояния и постоянно меняйте его, но мой вопрос в основном касается влияния предложения where на время.
В результате ленивой оценки код в каждой из строк 7–9 запускается только в том случае, если значение соответствующей привязки оценивается/используется в ходе оценки кода для совпадающего случая. Так:
newStatus
запускает строку 7, но строки 8-9 не запускаются.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
-предложении (или даже допустимо/значимо) для каждого случая. Однако с такими маленькими помощниками этот конкретный пример может быть более четко написан без каких-либо помощников:
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
все четыре из них (ваш исходный код и эти три варианта) компилируются в идентичный низкоуровневый код, поэтому используйте то, что вы считаете наиболее понятным.
Это домашнее задание?