На этот вопрос уже есть несколько других очень хороших ответов, объясняющих, как решить вашу проблему. Я не хочу этого делать; вместо этого я буду go просматривать каждую строку вашего кода, постепенно исправлять проблемы и, надеюсь, помочь вам лучше понять Haskell.
Сначала я скопирую ваш код для удобства:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z do
Bool check <- x == y
Bool nextC <- y == z
if check == nextC
then True
else False
Первая строка - это подпись типа; это уже хорошо объяснено в других ответах, поэтому я пропущу это и go перейду к следующей строке.
Во второй строке вы определяете свою функцию. Первое, что вы пропустили, это то, что вам нужен знак равенства для определения функции: синтаксис определения функции - functionName arg1 arg2 arg3 … = functionBody
, и вы не можете удалить =
. Итак, давайте исправим это:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = do
Bool check <- x == y
Bool nextC <- y == z
if check == nextC
then True
else False
Следующая ошибка использует нотацию do
. do
нотация печально известна тем, что вводит в заблуждение новичков, поэтому не стесняйтесь использовать ее неправильно. В Haskell нотация do
используется только в определенных c ситуациях, когда необходимо выполнять последовательность операторов построчно, особенно если у вас есть побочный эффект (например, печать на консоли ) который выполняется с каждой строкой. Понятно, что это здесь не подходит - все, что вы делаете, это сравниваете некоторые значения и возвращаете результат, который вряд ли требует построчного выполнения. Итак, давайте избавимся от этого do
:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let Bool check = x == y
Bool nextC = y == z
in
if check == nextC
then True
else False
(я также заменил привязку <-
на let … in …
, поскольку <-
можно использовать только внутри блока do
. )
Далее еще одна проблема: Bool check
недействительно Haskell! Возможно, вы знакомы с этим синтаксисом из других языков, но в Haskell тип всегда указывается с использованием ::
и часто с сигнатурой типа. Поэтому я удалю Bool
перед именами и добавлю вместо них сигнатуры типов:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let check :: Bool
check = x == y
nextC :: Bool
nextC = y == z
in
if check == nextC
then True
else False
Теперь, на данный момент, ваша программа совершенно корректна Haskell - вы сможете скомпилировать ее, и это будет работать. Но есть еще несколько улучшений, которые вы можете сделать.
Для начала вам не нужно включать типы - Haskell имеет вывод типов, и в большинстве случаев нормально не включать типы (хотя это традиционно включить их для функций). Итак, давайте избавимся от типов в let
:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let check = x == y
nextC = y == z
in
if check == nextC
then True
else False
Теперь check
и nextC
используются только в одном месте - присвоение им имен ничего не делает, а только служит сделать код менее читабельным. Поэтому я добавлю определения check
и nextC
в их употребления:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
if (x == y) == (y == z)
then True
else False
Наконец, я вижу, что у вас есть выражение вида if <condition> then True else False
. Это избыточно - вы можете просто вернуть <condition>
с тем же значением. Итак, давайте сделаем это:
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = (x == y) == (y == z)
Это намного, намного лучше, чем код, с которого вы начали!
(На самом деле есть еще одно улучшение, которое вы можете внести в этот код. Точка, должно быть очевидно, что в вашем коде есть ошибка. Можете ли вы найти ее? И если да, то можете ли вы ее исправить? Подсказка: вы можете использовать оператор &&
для 'и' двух логических значений вместе.