Я изучаю Haskell и пишу простую программу. Теперь у меня возникла проблема, которая для меня довольно запутанная. Вот код:
data VariableName = X|Y deriving Show
getValue :: VariableName -> Int
getValue X = 5
getValue Y = 13
data Expression = Constant|Variable|Add|Multiply deriving Show
evaluate :: Expression -> Int
evaluate Constant x = x
evaluate Variable x = getValue x
evaluate Add x y = x+y
evaluate Multiply x y = x * y
Я ожидаю вывод:
Constant 20 = 20
но я получаю
*Main> evaluate Constant 20
<interactive>:79:1: error:
Variable not in scope: evaluate :: t0 -> Integer -> t
<interactive>:79:10: error: Data constructor not in scope: Constant
Но когда, например: я пишу
*Main> getValue X
5
Какой правильный ответ. Я только что начал Haskell, и это меня очень сбивает с толку. Некоторая помощь будет высоко оценена.
Кроме того, Expression, такой как Constant | Variable | Add | Multiply, кажется, не имеет особого смысла, в первую очередь, я бы ожидал, например, Constant Int | Variable VariableName | Add Expression Expression | Multiply Expression Expression, поскольку тогда это параметры выражения.
Я предполагаю, что вы вводите этот код построчно через ghci, поскольку код evaluate :: Expression -> Int; evaluate Constant x = x даже не должен компилироваться вместе с комментариями Виллема.
@WillemVanOnsem Я пытался добавить все возможные комбинации скобок, но все равно выдает ту же ошибку. :/





Давайте посмотрим на ошибки:
Variable not in scope: evaluate :: t0 -> Integer -> t Data constructor not in scope: Constant
Это означает, что вы не определили функцию evaluate и конструктор Constant (хотя явно это сделали). Но вы говорите, что когда вы используете getValue и X, они работают?
Это не похоже на (чрезвычайно распространенную) многострочную путаницу ghci, как это предлагается в комментарии. Во-первых, ошибка, которую вы получаете от этого, имеет тенденцию быть non-exhaustive patterns, а это не то, что вы получаете. Во-вторых, ваше приглашение ghci читает *Main> вместо Prelude>, что означает, что вы :loaded файл. Упомянутый файл просто не определил код, который вы ожидаете от него.
Я предполагаю, что вы написали первую часть кода в файле, затем :load правильно его отредактировали, затем изменили файл и забыли использовать :reload, поэтому сделанные вами изменения никогда не загружались.
Другая возможность заключается в том, что вы поместили module Main (VariableName (..), getValue) where в начало вашего файла и забыли добавить в него свои новые экспорты. Но это кажется менее вероятным.
Если ничего из вышеперечисленного не работает, просто попробуйте закрыть ghci, снова открыть его и :load заново создать файл.
Даже после того, как вы устраните эту проблему, вы столкнетесь с рядом других ошибок, в основном связанных со скобками. В Haskell, когда вы пишете что-то вроде этого:
evaluate Constant 20
Это означает «вызвать функцию evaluate и передать ей два аргумента: Constant и 20». Это подразумевает evaluate :: Expression -> Int -> Int, но вам действительно нужен evaluate :: Expression -> Int. Итак, вам нужны скобки:
evaluate (Constant 20)
Это означает «вызвать конструктор Constant с одним аргументом 20 и передать это значение в качестве единственного аргумента в evaluate».
Вы должны сделать это изменение не только на месте вызова, но и в определении. В настоящее время у вас есть:
evaluate :: Expression -> Int
evaluate Constant x = x
evaluate Variable x = getValue x
evaluate Add x y = x+y
evaluate Multiply x y = x * y
Каждый из этих шаблонов ожидает разное количество аргументов: первые два ожидают два аргумента, а последние два ожидают три аргумента. Проблема в том, что x и y рассматриваются как аргументы функции, а не как конструкторы. Чтобы изменить это, вам нужны круглые скобки:
evaluate :: Expression -> Int
evaluate (Constant x) = x
evaluate (Variable x) = getValue x
evaluate (Add x y) = x+y
evaluate (Multiply x y) = x * y
Последнее изменение, которое вам нужно внести, находится в определении конструктора: вам нужно сообщить конструкторам, что они в первую очередь принимают аргументы. В настоящее время ваше определение данных выглядит так (я добавил форматирование):
data Expression = Constant
| Variable
| Add
| Multiply
deriving Show
Ни один из этих конструкторов в настоящее время не принимает аргументы: это значения (например, True, X, Nothing и т. д.), а не конструкторы значений. Это не то, что вы хотите. Вам нужно указать типы аргументов для каждого конструктора, например:
data Expression = Constant Int
| Variable VariableName
| Add Int Int
| Multiply Int Int
deriving Show
Вам нужно добавить круглые скобки, сейчас похоже, что вы определяете
evaluate Constant xс двумя переменными.