[Haskell] Классы и типы
От: Tonal- Россия www.promsoft.ru
Дата: 08.01.09 10:53
Оценка:
Есть два похожих типа:
data LTree Int String = LTree Int String [LTree Int String]
data MTree Int String = MTree Int String Map String (LTree Int String)

Хочется сделать обобщённые функции для раоты и их компанентами.
В случае i и n всё просто:
class GetComp x where
  getNA :: x -> (Int, String)

instance GetComp LTree where
  getNA (LTree i s _) = (i, s)

instance GetComp MTree where
  getNA (MTree i s _) = (i, s)

А можно ли записать функцию, которая отдаёт третий компанент, список для LTree и мап для MTree?

И как быть если не хочется указывать типы Int и String явно?
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re: [Haskell] Классы и типы
От: deniok Россия  
Дата: 08.01.09 11:50
Оценка: 22 (2)
Здравствуйте, Tonal-, Вы писали:

T>Есть два похожих типа:

T>
T>data LTree Int String = LTree Int String [LTree Int String]
T>data MTree Int String = MTree Int String Map String (LTree Int String)
T>


T>А можно ли записать функцию, которая отдаёт третий компанент, список для LTree и мап для MTree?


Если имеется в виду
data LTree = LTree Int String [LTree]
data MTree = MTree Int String (Map String MTree)

то можно обобщить так
data AnyTree cont = Cons Int String (cont (AnyTree cont)) 

-- те типы, которые были раньше
type LTree' = AnyTree []
type MTree' = AnyTree (Map String)

-- требуемая функция не зависит от конкретного контейнера
getSubTree (Cons _ _ xs) = xs

Мораль: параметрический полиморфизм в Хаскеле предпочтительней полиморфизма классов типов и стоит его использовать максимально
Re[2]: [Haskell] Классы и типы
От: Аноним  
Дата: 08.01.09 17:01
Оценка:
Здравствуйте, deniok, Вы писали:

D>Если имеется в виду

D>
D>data LTree = LTree Int String [LTree]
D>data MTree = MTree Int String (Map String MTree)
D>


ИМХО, там не совсем так. Там скорее

data AnyTree f = AnyTree Int String (f LTree)
type LTree = AnyTree []
type MTree = AnyTree (Map String)
Re[2]: [Haskell] Классы и типы
От: Tonal- Россия www.promsoft.ru
Дата: 09.01.09 09:16
Оценка:
Здравствуйте, deniok, Вы писали:
D>то можно обобщить так
D>
D>data AnyTree cont = Cons Int String (cont (AnyTree cont))

Классно, спасибо!

Ещё вопрос, как для этого типа написать функцию объединения узлов?
Т.е. раньше у меня было 2 функции:
munion (MTree n1 a1 ms1) (MTree n2 a2 ms2) 
  | n1 < n2 =   MTree n1 a1 ms
  | otherwise = MTree n2 a2 ms
  where
    ms = M.union ms1 ms2
lunion (LTree n1 a1 xs1) (LTree n2 a2 xs2) 
  | n1 < n2 =   LTree n1 a1 xs
  | otherwise = LTree n2 a2 xs
  where
    xs = xs1 ++ xs2

Хочится их тоже как-то унифицировать...
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[3]: [Haskell] Классы и типы
От: palm mute  
Дата: 09.01.09 10:18
Оценка: 12 (2)
Здравствуйте, Tonal-, Вы писали:

T>Ещё вопрос, как для этого типа написать функцию объединения узлов?


Если хочется одноименных функций, от классов типов далеко не убежишь.
В данном случае можно воспользоваться готовым классом:
import Data.Monoid

treeUnion (Cons n1 a1 ms1) (Cons n2 a2 ms2) 
  | n1 < n2 =   Cons n1 a1 ms
  | otherwise = Cons n2 a2 ms
  where
    ms = ms1 `mappend` ms2


На исходный вопрос возможны другие ответы, посмотри в сторону Multi-parameter type classes (работает в старых версиях GHC) или type families, associated types etc (работает только в последних версиях).

Ну и не мешало бы убедиться, что в программе действительно нужно 2 разных вида дерева, различающихся только контейнером для детей.
Re[4]: [Haskell] Классы и типы
От: deniok Россия  
Дата: 09.01.09 10:39
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>На исходный вопрос возможны другие ответы, посмотри в сторону Multi-parameter type classes (работает в старых версиях GHC) или type families, associated types etc (работает только в последних версиях).


Можно ещё и в сторону Scrap Your Boilerplate посмотреть, там много способов делать обобщенную обработку богато организованных деревьев.

PM>Ну и не мешало бы убедиться, что в программе действительно нужно 2 разных вида дерева, различающихся только контейнером для детей.


+1, мне вся задача кажется слегка искусственной
Re[4]: [Haskell] Классы и типы
От: Аноним  
Дата: 09.01.09 18:21
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Если хочется одноименных функций, от классов типов далеко не убежишь.


В списке отвергнутых proposals для Haskell' есть и пункт "убрать классы". Я последнее время прихожу к выводу, что это правильно.
Re[5]: [Haskell] Классы и типы
От: deniok Россия  
Дата: 09.01.09 18:23
Оценка:
Здравствуйте, http://migmit.vox.com/, Вы писали:

HMV>В списке отвергнутых proposals для Haskell' есть и пункт "убрать классы". Я последнее время прихожу к выводу, что это правильно.


being lazy without class
Re[5]: [Haskell] Классы и типы
От: palm mute  
Дата: 09.01.09 18:43
Оценка:
Здравствуйте, http://migmit.vox.com/, Вы писали:

HMV>В списке отвергнутых proposals для Haskell' есть и пункт "убрать классы". Я последнее время прихожу к выводу, что это правильно.


А что вместо классов? Ручной dictionary passing? ML-like модули? Что-то еще?
Re[6]: [Haskell] Классы и типы
От: Аноним  
Дата: 10.01.09 19:59
Оценка:
PM>А что вместо классов? Ручной dictionary passing? ML-like модули? Что-то еще?

Dictionary passing + default arguments. Основное применение классов сохранится (можно даже нотацию оставить), плюс можно будет абстрагироваться по классу. Сейчас написать функцию, скажем (сигнатура от балды),
cls a => (forall b. cls b => b) -> b
невозможно, потому что нужен конкретный класс вместо cls. И никакие расширения не спасут. Можно воспользоваться жутковатой техникой с GADT, я её приводил в своём журнале. Но, скажем, как можно абстрагироваться не по произвольному классу, а по классу, для которого объявлен
instance (cls a, cls b) => cls (a, b)
, я не представляю. А оно бывает реально надо.

Так что, нужно сделать классы обычными типами (вместо
class Eq a where (==) :: a -> a -> Bool
сделать
data Eq a = Eq {(==) :: a -> a -> Bool}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.
Re[7]: [Haskell] Классы и типы
От: Курилка Россия http://kirya.narod.ru/
Дата: 10.01.09 20:06
Оценка:
Здравствуйте, http://migmit.vox.com/, Вы писали:

[cut]

HMV>Так что, нужно сделать классы обычными типами (вместо
class Eq a where (==) :: a -> a -> Bool
сделать
data Eq a = Eq {(==) :: a -> a -> Bool}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.


Не раскроешь, что тут подразумевается под "значениями по умолчанию"? В голову приходят только подобное для параметров во всяких PHP/Basic...
Re[8]: [Haskell] Классы и типы
От: Аноним  
Дата: 10.01.09 20:35
Оценка: 5 (1)
HMV>>Так что, нужно сделать классы обычными типами (вместо
class Eq a where (==) :: a -> a -> Bool
сделать
data Eq a = Eq {(==) :: a -> a -> Bool}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.


К>Не раскроешь, что тут подразумевается под "значениями по умолчанию"? В голову приходят только подобное для параметров во всяких PHP/Basic...


Фактически, речь о том, что происходит сейчас. Когда ты пишешь функцию с сигнатурой
C a => a -> Bool
, это, по существу, означает, что кроме параметра типа "a" эта функция принимает ещё один параметр — словарь. Я бы хотел сделать это более явным — сделать C не "классом", а типом кайнда * -> *, и дать возможность, когда захочется, передать этот параметр в функцию столь же явно; при этом, если НЕ захочется передавать явно, использовать, как и сейчас, словарь по умолчанию, определяемый по типу "a".
Re[9]: [Haskell] Классы и типы
От: deniok Россия  
Дата: 10.01.09 20:45
Оценка:
Здравствуйте, http://migmit.vox.com/, Вы писали:

HMV>>>Так что, нужно сделать классы обычными типами (вместо
class Eq a where (==) :: a -> a -> Bool
сделать
data Eq a = Eq {(==) :: a -> a -> Bool}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.


К>>Не раскроешь, что тут подразумевается под "значениями по умолчанию"? В голову приходят только подобное для параметров во всяких PHP/Basic...


HMV>Фактически, речь о том, что происходит сейчас. Когда ты пишешь функцию с сигнатурой
C a => a -> Bool
, это, по существу, означает, что кроме параметра типа "a" эта функция принимает ещё один параметр — словарь. Я бы хотел сделать это более явным — сделать C не "классом", а типом кайнда * -> *, и дать возможность, когда захочется, передать этот параметр в функцию столь же явно; при этом, если НЕ захочется передавать явно, использовать, как и сейчас, словарь по умолчанию, определяемый по типу "a".


Какой твой propousal, скажем, для
testEq ?? -> a -> a -> y
testEq | (?? x  y)  = "Good"
       | otherwise = "Bad"

Как тут делать?
Re[10]: [Haskell] Классы и типы
От: deniok Россия  
Дата: 10.01.09 20:47
Оценка:
Здравствуйте, deniok, Вы писали:

testEq ?? -> a -> a -> String
testEq | (?? x  y)  = "Good"
       | otherwise = "Bad"

String, ясное дело.
Re[10]: [Haskell] Классы и типы
От: Аноним  
Дата: 10.01.09 22:46
Оценка:
D>Какой твой propousal, скажем, для
D>
D>testEq ?? -> a -> a -> y
D>testEq | (?? x  y)  = "Good"
D>       | otherwise = "Bad"
D>

D>Как тут делать?

Как сейчас. Просто текущая запись будет сахаром, который можно обойти, скажем, так:
f :: a -> Bool
f x = instance Eq a where x == y = False
      in x == x


Это, конечно, выморочный пример — будет то же самое, что и const False — но, думаю, идея ясна.

Потом, например, такое:
data P x = ... -- какая-то реализация
instance (t x, forall a b. (t a, t b) => t (a, b)) => t (P x)


Потом это можно, скажем, применить к t = Eq. Или Ord. И забесплатно из instance Eq x получить instance Eq (P x) — и то же самое для Ord (коль скоро instance (t a, t b) => t (a, b) у нас уже есть).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.