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 явно?
Здравствуйте, 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)
Здравствуйте, 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 разных вида дерева, различающихся только контейнером для детей.
Здравствуйте, 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' есть и пункт "убрать классы". Я последнее время прихожу к выводу, что это правильно.
Здравствуйте, http://migmit.vox.com/, Вы писали:
HMV>В списке отвергнутых proposals для Haskell' есть и пункт "убрать классы". Я последнее время прихожу к выводу, что это правильно.
Здравствуйте, 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}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.
HMV>>Так что, нужно сделать классы обычными типами (вместо
class Eq a where (==) :: a -> a -> Bool
сделать
data Eq a = Eq {(==) :: a -> a -> Bool}
), сделать достаточно богатый язык для задания значений по умолчанию, и зажить счастливо.
К>Не раскроешь, что тут подразумевается под "значениями по умолчанию"? В голову приходят только подобное для параметров во всяких PHP/Basic...
Фактически, речь о том, что происходит сейчас. Когда ты пишешь функцию с сигнатурой
C a => a -> Bool
, это, по существу, означает, что кроме параметра типа "a" эта функция принимает ещё один параметр — словарь. Я бы хотел сделать это более явным — сделать C не "классом", а типом кайнда * -> *, и дать возможность, когда захочется, передать этот параметр в функцию столь же явно; при этом, если НЕ захочется передавать явно, использовать, как и сейчас, словарь по умолчанию, определяемый по типу "a".
Здравствуйте, 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"
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) у нас уже есть).