Как правильно реализовать вспомогательную функцию в Haskell - PullRequest
3 голосов
/ 01 апреля 2020

Описание функции gridList:

Принимает два входа Integer, x и y и возвращает список кортежей, представляющих координаты каждой ячейки из (1,1) до (x,y).

Пример вывода

$> gridList 3 3
$> [(1,1),(2,1),(3,1),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]

Исходный код

gridList :: Integer -> Integer -> [(Integer,Integer)]
gridList 1 1 = [(1,1)]
gridList 1 y = helper 1 y
gridList x y = (helper x y) ++ gridList (x-1) y
  where 
    helper :: Integer -> Integer -> [(Integer, Integer)]
    helper x 1 = [(x,1)]
    helper x y = (x,y) : (helper x (y-1))

Вопрос: Код не компилируется, давая следующее error: Variable not in scope, ссылаясь на строку 3, где впервые вводится помощник. Почему where не решает эту проблему?

Спасибо

Ответы [ 2 ]

4 голосов
/ 01 апреля 2020

В Haskell, where связанные определения находятся в области видимости только в уравнении непосредственно над блоком where. Это означает, что если вы определяете функцию, используя несколько уравнений, каждое из них получает отдельный блок where.

В вашем случае определение helper входит в область действия только для третьего уравнения (строка 4 ), но не для первых двух.

Чтобы использовать одно и то же определение helper для всех ветвей, измените определение с трех отдельных уравнений на выражение case:

gridList :: Integer -> Integer -> [(Integer,Integer)]
gridList x y = case (x, y) of
    (1, 1) -> [(1,1)]
    (1, _) -> helper 1 y
    _ -> (helper x y) ++ gridList (x-1) y
  where 
    helper :: Integer -> Integer -> [(Integer, Integer)]
    helper x 1 = [(x,1)]
    helper x y = (x,y) : (helper x (y-1))
4 голосов
/ 01 апреля 2020

Проблема в том, что область действия условия where охватывает только последнее уравнение. Я бы обычно предлагал использовать выражение для случая вместо нескольких уравнений. Однако, поскольку вы выполняете сопоставление с шаблоном по двум аргументам, для выполнения этого здесь требуется либо сопоставление по паре, как в ответе Федора Сойкина , либо вложенные выражения падежа:

gridList :: Integer -> Integer -> [(Integer,Integer)]
gridList x y = case x of
    1 -> case y of
        1 -> [(1,1)]
        _ -> helper 1 y
    _ -> helper x y ++ gridList (x-1) y
    where 
    helper :: Integer -> Integer -> [(Integer, Integer)]
    helper x 1 = [(x,1)]
    helper x y = (x,y) : helper x (y-1)

наименее инвазивный обходной путь, вероятно, использует шаблон защиты:

gridList :: Integer -> Integer -> [(Integer,Integer)]
gridList x y
    | 1 <- x, 1 <- y = [(1,1)]
    | 1 <- x = helper 1 y
    | otherwise = helper x y ++ gridList (x-1) y
    where
    helper :: Integer -> Integer -> [(Integer, Integer)]
    helper x 1 = [(x,1)]
    helper x y = (x,y) : helper x (y-1)

Как подсказывает Луки , другие варианты включают вытягивание helper из предложения where и выдвижение уравнений внутри него (gridList = go where go 1 1 = [(1,1)] -- etc.).

...