kzen.dev
  • Вопросы
  • Метки
  • Пользователи
Оповещения
Вознаграждения
Регистрация
После регистрации, сможете получать уведомления об ответах и комментариях на Ваши вопросы.
Вход
Если у Вас уже есть аккаунт, войдите чтобы проверить новые уведомления.
Тут будут вознаграждения за добавленные вопросы, ответы и комментарий.
Дополнительно
Источник
Редактировать
 Clinton
Clinton
Вопрос

Haskell: Ограничение равенства в экземпляре

Читал анонс ClassyPrelude и попал сюда:

instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
    filter = filterFunc

Далее автор упомянул, что это не будет работать:

instance (CanFilterFunc b a) => CanFilter (c -> c) a where
    filter = filterFunc

Что, на мой взгляд, вполне логично, поскольку c совершенно не связано с ограничением слева.

Однако то, что не упоминается в статье, и то, что я не понимаю, - это почему это не работает:

instance (CanFilterFunc b a) => CanFilter (b -> b) a where
    filter = filterFunc

Может ли кто-нибудь объяснить, чем это отличается от первого упомянутого определения? Возможно, будет полезен пример с выводом типов в GHC?

33 2012-07-19T03:55:58+00:00 2
 Clinton
Clinton
Редактировал вопрос 19-го июля 2012 в 6:28
Программирование
haskell
Решение / Ответ
 kosmikus
kosmikus
19-го июля 2012 в 6:02
2012-07-19T06:02:24+00:00
Дополнительно
Источник
Редактировать
#16727751

Майкл уже дал хорошее объяснение в своей статье в блоге, но я попробую проиллюстрировать его на (надуманном, но относительно небольшом) примере.

Нам нужны следующие расширения:

{-# LANGUAGE FlexibleInstances, TypeFamilies #-}

Определим класс, более простой, чем CanFilter, с одним параметром. Я определяю два экземпляра класса, поскольку хочу продемонстрировать разницу в поведении двух экземпляров:

class Twice1 f where
  twice1 :: f -> f

class Twice2 f where
  twice2 :: f -> f

Теперь давайте определим по экземпляру для каждого класса. Для Twice1 мы фиксируем, чтобы переменные типа были непосредственно одинаковыми, а для Twice2 мы разрешаем им быть разными, но добавляем ограничение на равенство.

instance Twice1 (a -> a) where
  twice1 f = f . f

instance (a ~ b) => Twice2 (a -> b) where
  twice2 f = f . f

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

class Example a where
  transform :: Int -> a

instance Example Int where
  transform n = n + 1

instance Example Char where
  transform _ = 'x'

Теперь мы подошли к тому моменту, когда можно увидеть разницу. Как только мы определим

apply1 x = twice1 transform x
apply2 x = twice2 transform x

и запросим у GHC выведенные типы, мы получим следующее

apply1 :: (Example a, Twice1 (Int -> a)) => Int -> a
apply2 :: Int -> Int

Почему так? Ну, экземпляр для Twice1 срабатывает только в том случае, если исходный и целевой тип функции совпадают. Для transform и данного контекста мы этого не знаем. GHC применит экземпляр только в том случае, если правая сторона совпадает, поэтому мы остаемся с неразрешенным контекстом. Если мы попытаемся сказать apply1 0, то будет выдана ошибка типа, говорящая о том, что для разрешения перегрузки недостаточно информации. В этом случае необходимо явно указать тип результата Int.

Однако в Twice2 экземпляр предназначен для любого типа функции. GHC немедленно разрешит его (GHC никогда не делает обратного хода, поэтому если экземпляр явно совпадает, то он всегда выбирается), а затем попытается установить предусловия: в данном случае ограничение равенства, которое заставит тип результата быть Int и позволит нам разрешить ограничение Example. Мы можем сказать apply2 0 без дополнительных аннотаций типа.

Таким образом, это довольно тонкий момент в разрешении экземпляров в GHC, и ограничение равенства здесь помогает GHC проверять типы таким образом, что пользователю требуется меньше аннотаций типов.

51
0
Хотите что-то узнать? Задавайте Ваш вопрос на нашем сайте
ru.kzen.dev
 srghma
srghma
17-го октября 2018 в 8:18
2018-10-17T20:18:11+00:00
Дополнительно
Источник
Редактировать
#16727752

завершить ответ @kosmikus

То же самое относится и к purescript - для корректного выведения типа необходимо ограничение равенства (можно попробовать здесь http://try.purescript.org).

module Main where

import Prelude

-- copied from https://github.com/purescript/purescript-type-equality/blob/master/src/Type/Equality.purs
class TypeEquals a b | a -> b, b -> a where
  to :: a -> b
  from :: b -> a

instance refl :: TypeEquals a a where
  to a = a
  from a = a

-----------------

class Twice1 f where
  twice1 :: f -> f

class Twice2 f where
  twice2 :: f -> f

instance mytwice1 :: Twice1 (a -> a) where
  twice1 f = f >>> f

instance mytwice2 :: TypeEquals a b => Twice2 (a -> b) where
  twice2 f = f >>> from >>> f

class Example a where
  transform :: Int -> a

instance exampleInt :: Example Int where
  transform n = n + 1

instance exampleChar :: Example Char where
  transform _ = 'x'

{--
-- will raise error
--   No type class instance was found for Main.Twice1 (Int -> t1)

apply1 x = twice1 transform x

-- to resolve error add type declaration
apply1 :: Int -> Int

--}

-- compiles without error and manual type declaration, has type Int -> Int automatically
apply2 x = twice2 transform x

Но в Идрисе вы'не

module Main

import Prelude

interface Twice f where
  twice : f -> f

Twice (a -> a) where
  twice f = f . f

interface Example a where
  transform : Int -> a

Example Int where
  transform n = n + 1

Example Char where
  transform _ = 'x'

-- run in REPL to see that it derives properly:

-- $ idris src/15_EqualityConstraint_Twice_class.idr
-- *src/15_EqualityConstraint_Twice_class> :t twice transform
-- twice transform : Int -> Int

-- Summary:
-- in idris you dont need equality constaint to derive type of such functions properly
 srghma
srghma
Редактировал ответ 18-го октября 2018 в 8:02
0
0
Хотите что-то узнать? Задавайте Ваш вопрос на нашем сайте
ru.kzen.dev
Похожие сообщества 3
Haskell
Haskell
1 646 пользователей
https://combot.org/chat/-1001043143583 Ссылки на полезные ресурсы: https://ruhaskell.org/links.html ; Информация о мероприятиях: https://gist.github.com/qnikst/a96cac661be80d126d0829f2ced1916e
Открыть telegram
Haskell Start
Haskell Start
902 пользователей
Чат для вопросов по основам хаскеля для совсем начинающих. Правила чата: http://bit.ly/λrules Остальные чаты перечислены тут: https://ruhaskell.org/links Wiki сообщества: http://bit.ly/λwiki (про редакторы там тоже написано)
Открыть telegram
Haskell CVs and Jobs
Haskell CVs and Jobs
556 пользователей
RuHaskell.org Discuss Haskell employers, vacancies and job market. Show your CV! Job postings are in @haskell_job General discussion in @haskellru, @haskell_learn, @haskell_en Offtop: @haskell_cv_blah Code of Conduct: http://bit.ly/λrules
Открыть telegram
Добавить вопрос
Категории
Все
Технологий
Культура / Отдых
Жизнь / Искусство
Наука
Профессии
Бизнес
Пользователи
Все
Новые
Популярные
1
Александр Македонский
Зарегистрирован 6 дней назад
2
Andrei Kalinin
Зарегистрирован 3 недели назад
3
Koroleva Ego
Зарегистрирован 1 месяц назад
4
Star Lenon
Зарегистрирован 1 месяц назад
5
Данил Жевнеров
Зарегистрирован 2 месяца назад
Хотите что-то узнать? Задавайте Ваш вопрос на нашем сайте
ru.kzen.dev
KO
RU
© kzen.dev 2023
Источник
stackoverflow.com
под лицензией cc by-sa 3.0 с атрибуцией