Конструктор данных вне области действия

Я изучаю 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, и это меня очень сбивает с толку. Некоторая помощь будет высоко оценена.

Вам нужно добавить круглые скобки, сейчас похоже, что вы определяете evaluate Constant x с двумя переменными.

Willem Van Onsem 19.01.2019 19:34

Кроме того, Expression, такой как Constant | Variable | Add | Multiply, кажется, не имеет особого смысла, в первую очередь, я бы ожидал, например, Constant Int | Variable VariableName | Add Expression Expression | Multiply Expression Expression, поскольку тогда это параметры выражения.

Willem Van Onsem 19.01.2019 19:36

Я предполагаю, что вы вводите этот код построчно через ghci, поскольку код evaluate :: Expression -> Int; evaluate Constant x = x даже не должен компилироваться вместе с комментариями Виллема.

Mor A. 19.01.2019 21:13

@WillemVanOnsem Я пытался добавить все возможные комбинации скобок, но все равно выдает ту же ошибку. :/

user1233156 20.01.2019 15:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
2 241
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Давайте посмотрим на ошибки:

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

Другие вопросы по теме