Перегрузка ( )

#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, поэтому мне пришлось бы определять ( ) как векторное произведение?