LINUX.ORG.RU

[haskell] type classes


0

1

как мне обойти следующие ограничения системы типов хаскеля.

есть у меня например класс

class C a where f :: a -> b -> a

я делаю инстанс этого класса, для типов T1 и Т2 data T1 = T1 data T2 = T2

instance C T1 where f T1 b = T1

instance C T2 where f T2 b = T1

система типов хаскеля, конечно же єтого не позволяет, так как сигнатура ф-и f :: a -> b -> a т.е. тип первого аргумента и результата - совпадают. а мне хотелось бі чего-то вроде f :: a1 -> b -> a2, где a1, a2 - инстансы класса С

как мне решить данную проблему?


Проявлю смелость предположить, что вопрос сформулирован криво и (f :: a1 -> b -> a2) требуется по a2 экзистенциальным, а не полиморфным.

В таком случае есть как минимум два выхода: мультипараметрические классы типов с функциональными зависимостями или семейства типов.

Раз.

class C a1 a2 | a1 -> a2 where
  f :: a1 -> b -> a2

data T1 = T1

data T2 = T2

instance C T1 T1 where
  f T1 b = T1

instance C T2 T1 where
  f T2 b = T1

Два.

class C a1 where
  type F a1
  f :: a1 -> b -> F a1

data T1 = T1

data T2 = T2

instance C T1 where
  type F T1 = T1
  f T1 b = T1

instance C T2 where
  type F T2 = T1
  f T2 b = T1
anonymous ()
Ответ на: комментарий от kyz

меня интересует второй способ. с объявлением типа. ссылки приветствуются.

kyz ()
Ответ на: комментарий от korvin_

>никак

нельзя быть таким категоричным. видишь, пришел человек и помог. хотя да, его решение нарушает ограничения стандарта 98-го года(по крайне мере в случае, когда сигнатура ф-и такая - f :: a b -> b -> F a b

но ключ "-XTypeFamilies" - исправил дело

kyz ()
Ответ на: комментарий от kyz

но ключ "-XTypeFamilies" - исправил дело

{-# LANGUAGE TypeFamilies #-}

И выглядит чище, и работать проще.

Miguel ★★★★★ ()
Ответ на: комментарий от anonymous

class C a where type F a :: * -> * f :: a b -> b -> F a b

каж сделать ограничение на то, что-бы F a b - был инстансом класса C

?

прикол в том, что я хочу, что-бы результат был обязательно инстаносом С. а данная конструкция позволяет возвращать любые типы

kyz ()
Ответ на: комментарий от kyz

прикол в том, что я хочу, что-бы результат был обязательно инстаносом С

А как тогда быть orphan instances — во время компиляции не известно какие типы могут быть инстансами данного класса, а динамической диспетчеризации хаскель не умеет.

Но если известно, можно сделать так:

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Typeable

class Typeable t => IsInstance t

class Typeable t => MyClass t where
  ok :: IsInstance r => t -> Maybe r
  ok = cast
  -- ...
  f  :: IsInstance r => t -> Maybe r

data T1 = T1 deriving ( Show, Typeable )
data T2 = T2 deriving ( Show, Typeable )

instance IsInstance T1
instance IsInstance T2

instance MyClass T1 where
  f T1 = ok T1

instance MyClass T2 where
  f T2 = ok T1

-- f T1 :: Maybe T1
-- > Just T1
-- 
-- f T1 :: Maybe T2
-- > Nothing

-- но написать что-то вроде
-- 
-- instance MyClass T2 where
--   f T2 = ok 1
--
-- не получится

почти haskell-98.

quasimoto ★★★★ ()
Ответ на: комментарий от anonymous

[code] class C a1 a2 b | a1 b -> a2 b where [/code]

можно ли сделать Экзистенциальный список для данного класса? я не могу придумать, как через forall записать все три параметра(а1, a2, b)

kyz ()
Ответ на: комментарий от anonymous

А чем сложность? Всё сказанное остается пока в силе.

да нет, я проверял. можно смело инициализировать F a b не инстансом прямоугольника

поэтому, я сейчас реализовал этот способ:

class C a1 a2 | a1 -> a2 where f :: a1 -> b -> a2

мне кто-то может объяснить что обозначает «| a1 -> a2» нигде в докне не могу найти.

ну и вопрос с эзистенциаольными типами остается открытым, я что-то такое написал, но не уверн что это правильно, и незнаю как с этим работать:

 data (Num a) => Rs a =  forall r1 r2 . (С r1 r2 a) => Rs (r1 a)

kyz ()
Ответ на: комментарий от kyz

Нужно что-то вроде этого?

class Fooable a where
    foo :: Fooable c => a -> b -> c

То есть чтобы foo могла возвращать любой инстанс класса Fooable?

Mihai-gr ()
Ответ на: комментарий от kyz

да нет, я проверял. можно смело инициализировать F a b не инстансом прямоугольника

Мой предыдущий пример, только несколько проще:

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Typeable

class Typeable t => C t where
  f  :: C r => t -> Maybe r

data T1 = T1 deriving ( Show, Typeable )
data T2 = T2 deriving ( Show, Typeable )

instance C T1 where
  f T1 = cast T1

instance C T2 where
  f T2 = cast T2

и тогда результатом f может быть только инстанс C.

мне кто-то может объяснить что обозначает «| a1 -> a2» нигде в докне не могу найти.

Это функционалная зависимость. Например:

class And a b c | a b -> c

data T
data F

instance And T T T
instance And T F F
instance And F y F

test = undefined :: And F F r => r

И тип test редуцируется до F в compile time. Т.е. так мы можем писать функции на типах в type level.

ну и вопрос с эзистенциаольными типами остается открытым

anonymous будет меня ругать, но, ИМХО, все эти навороты тут совсем не нужны :)

quasimoto ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.