#haskell #typeclass
#haskell #класс типов
Вопрос:
Я пытаюсь определить Vector3
тип данных в Haskell и разрешить ( )
использовать для него оператор. Я попробовал следующее:
data Vector3 = Vector3 Double Double Double
Vector3 x y z Vector3 x' y' z' = Vector3 (x x') (y y') (z z')
Но ghci жалуется на неоднозначное возникновение ( )
. Я не понимаю, почему вхождение неоднозначно; конечно, проверка типов может сделать вывод, что x
, x'
, y
и т. Д. Имеют тип Double
, и, следовательно, правильный оператор для их использования есть Prelude.
?
Я знаю, что мог бы создать Vector3
экземпляр Num
класса типов, но это слишком ограничительно для меня; Я не хочу определять умножение вектора на другой вектор.
Ответ №1:
Единственный способ перегрузить имя в Haskell — это использовать классы типов, поэтому у вас есть три варианта:
- Создайте
Vector
экземплярNum
и просто верните умножениеerror
. - Используйте что-то вроде числовой прелюдии, которая определяет более детализированные числовые классы.
- Выберите какое-нибудь другое имя, например
. .
, или что-то подобное для сложения векторов.
Комментарии:
1. спасибо, что указали на числовую прелюдию; знаете ли вы какое-нибудь место, где это задокументировано?
2. @zodiac: Справочная документация доступна по ссылке, которую я разместил, просто прокрутите страницу вниз и нажмите на имя модуля. Алгебра. Аддитивный подход выглядит хорошим началом для этого примера добавления векторов.
3. Пакет Conal Elliott
vector-space
намного легче, чемnumeric-prelude
. Для добавления векторов определите экземплярAdditiveGroup
.4. спасибо всем за ваши полезные ответы; но кто-нибудь знает, почему появление ( ) неоднозначно (т.Е. Мой код действительно работает, если я использую «Prelude. » и «Main. »
5. @zodiac: это неоднозначно, потому что у вас есть два
( )
в области видимости. Тот, который вы определили сами, и тот, который из прелюдии. Таким образом, без уточнения компилятор не знает, какой из них вы хотите использовать.
Ответ №2:
Я знаю, что мог бы создать
Vector3
экземплярNum
класса типов, но это слишком ограничительно для меня; Я не хочу определять умножение вектора на другой вектор.
Однако это было бы самым простым решением. Вы можете определить умножение как
(*) = error "vector multiplication not implemented"
Подумайте о векторных операциях, которые вы получите бесплатно!
Комментарии:
1. На самом деле вам не нужны никакие параметры.
error :: String -> a
.2. Вы получите
-
, если определитеnegate
. Вы получаетеsum
. Хорошо, может быть, не так уж и здорово, но классы типов — это «правильный» способ перегрузки в Haskell.3. Основная проблема с созданием векторов в качестве
Num
экземпляра заключается в том, что вы хотели бы определить умножение, но не какVector->Vector->Vector
, а какField->Vector->Vector
илиNum a => a->Vector->Vector
.4. Нет ничего плохого в том, чтобы определять умножение как скалярное произведение и использовать другой оператор для умножения со скаляром.
5. @Landei Я считаю, что ( ) под Num будет иметь тип v -> v -> v, поэтому мне пришлось бы определять ( ) как векторное произведение?