Почему возврат строки не считается выражением типа Show x?

Может ли кто-нибудь помочь мне понять, почему этот код вызывает ошибку компиляции?

hello :: (Show x) => x
hello = "Hello"

Я думал, что String обладает свойствами Show, поэтому функция должна возвращать String? Вот сообщение об ошибке:

• Couldn't match expected type ‘x’ with actual type ‘[Char]’
  ‘x’ is a rigid type variable bound by
    the type signature for:
      hello :: forall x. Show x => x
    at script.hs:160:1-25
• In the expression: "Hello"
  In an equation for ‘hello’: hello = "Hello"
• Relevant bindings include
    hello :: x (bound at script.hs:161:1)

Что вы пытаетесь достичь? Распечатать сообщение? Привести строку к любому типу Show? Привести любой тип Show к строке?

Aplet123 18.12.2020 02:02
"Hello" — это строка. Используя сигнатуру Show x => x, вы обещаете, что для любого x, являющегося членом класса типов Show, ваша функция выдаст значение, но это обещание не выполняется, поскольку вы делаете это только в том случае, если x ~ String.
Willem Van Onsem 18.12.2020 02:02

См. также Почему Num может вести себя как Fractional?.

Daniel Wagner 18.12.2020 22:43

@ Aplet123 Я просто играл с сигнатурами универсального типа, я не пытался ничего приводить. Моей единственной целью было заставить его скомпилироваться :) Но я неправильно понял, что на самом деле означают сигнатуры универсальных типов в Haskell. Сейчас прояснилось.

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

Ответы 1

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

Ваша подпись типа не означает то, что вы думаете.

Из вашего объяснения кажется, что вы читаете эту подпись примерно так: «Я собираюсь вернуть вам значение некоторого типа x, у которого есть экземпляр Show. Я не буду говорить вам, какого именно типа это будет, но я обещаю, что у него будет экземпляр Show"

Но на самом деле это означает: «выберите тип, любой тип, просто убедитесь, что он имеет экземпляр Show, и я обещаю, что верну вам значение этого типа».

Другими словами, когда функция является универсальной, именно вызывающая функция выбирает, каким будет универсальный тип, а не реализатор.

Это имеет большой смысл. Я смешивал концепцию классов типов Haskell с интерфейсами из императивных языков, таких как Java.

cgoates 19.12.2020 23:55

Что ж, классы типов на самом деле очень похожи на интерфейсы в Java, особенно в этом конкретном случае, когда класс типов имеет один параметр. Ваша функция будет примерно эквивалентна чему-то вроде X hello<X extends IShow>() в Java.

Fyodor Soikin 20.12.2020 00:40

@FyodorSoikin, на самом деле, в данном случае они не одинаковы. Java не поддерживает полиморфизм возвращаемого типа, за исключением того, что понял ОП.

is7s 20.12.2020 22:06

Разве это пример возвращаемого полиморфного метода @is7s?

Fyodor Soikin 21.12.2020 15:02

Я не говорил, что Java вообще не поддерживает полиморфизм возвращаемого типа. Я сказал, что он поддерживает это только так, как это понял ОП. В примере, на который вы ссылаетесь, emptyList() всегда будет возвращать конкретное значение и не зависит от контекста. Что эквивалентно 1-му определению в вашем ответе. И это не эквивалентно тому, как полиморфизм возвращаемого типа работает в классах типов.

is7s 21.12.2020 16:19

На самом деле emptyList() вернет значение типа, которое выбирает вызывающая сторона. Я имею в виду, что он будет обернут в List<>, но элемент списка, который является общим параметром функции, выбирается вызывающей стороной. emptyList сам не выбирает свой общий параметр, это делает вызывающая сторона. Это эквивалентно моему второму определению, а не первому.

Fyodor Soikin 21.12.2020 16:39

В своем комментарии я сказал, что emptyList() всегда будет возвращать конкретное значение, а не конкретный тип. Это все еще не то, как работают классы типов, и все еще эквивалентно вашему 1-му определению :)

is7s 21.12.2020 17:29

Это означает только то, что в Java нет классов типов, т. е. разное поведение в зависимости от типов. Но у него все еще есть параметрический полиморфизм, в том числе и в возвращаемом типе. И это точно так же, как в Haskell. Сравните emptyList() с emptyList :: [a]; emptyList = [] в Java.

Fyodor Soikin 21.12.2020 17:45

Думаю, здесь мы согласны. Одно из основных различий между интерфейсами ООП и классами типов заключается в том, как они ведут себя при полиморфизме возвращаемых типов. И причиной, по которой я начал это, было ваше утверждение выше: «классы типов на самом деле очень похожи на интерфейсы в Java, особенно в этом конкретном случае, когда класс типов имеет один параметр», что не является точным. А еще я нигде не утверждал, что Java не поддерживает параметрический полиморфизм. Ваше здоровье.

is7s 21.12.2020 17:53

Разница между типами возврата в Haskell и большинстве языков ООП также хорошо объясняется в этом ответе на аналогичный вопрос

cgoates 10.01.2021 00:10

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