#haskell #where-clause
#haskell #where-предложение
Вопрос:
Я получил следующий фрагмент кода, который, как я знаю, работает, но я совершенно новичок в 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] используется через стандартный предикат set.
Вопрос 1) :
- Допустим, случай 2 имеет значение true. Выполняет ли Haskell строки 8 и 9 ?
- Допустим, случай 3 имеет значение true. Выполняет ли Haskell строку 7?
Вопрос 2) :
- Может ли у guard быть свой собственный where?
- Есть ли лучший способ сделать это на самом деле?
Комментарии:
1. Это домашнее задание?
2. @WillemVanOnsem Фактическим домашним заданием было «перевести» предикат f3 из Prolog в Haskell. Именно так я и придумал, и мне было интересно, не экономит ли то, как я это делаю, время или что-то в этом роде. Кстати, мне приходится постоянно переносить аргумент status и изменять его, но мой вопрос в основном касается временного воздействия предложения where.
Ответ №1:
В результате отложенной оценки код в каждой из строк 7-9 выполняется только в том случае, если значение соответствующей привязки вычисляется / используется в ходе оценки кода для случая, который соответствует. Итак:
- Если случай 1 имеет значение true, то ни одна из строк 7-9 не выполняется.
- Если случай 1 имеет значение false, но случай 2 имеет значение true, то вычисление
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
версией -clause что-то не так, и нет ничего необычного в написании кода на Haskell, где используется только подмножество привязок в where
-clause (или даже допустимых / значимых) для каждого случая. С такими маленькими помощниками этот конкретный пример может быть более четко написан без каких-либо помощников, хотя:
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
все четыре из них (ваш исходный код и эти три варианта) компилируются в идентичный низкоуровневый код, поэтому используйте тот, который вы считаете наиболее понятным.