Vladislav
А пока что их не то что никто не заимплементил, никто и proposal не написал толком.
A64m
пропозал можно взять из кладбища пропозалов
A64m
когда рекорды обсуждали несколько лет назад, там этих пропозалов понаписали
A64m
не могу сказать, на любой вкус, конечно, потому что буквально, ни одного нормального так и не придумали
A64m
по крайней мере каждый надет себе там такой, который сможет ненавидеть
Vladislav
Но уж получше чем убогое некомпозабельное API с keyword arguments, небось
Vladislav
Что его делает некомпозабельным, кстати?
A64m
ну вроде понятно из примера композабельного, где иголка это парсер, парсящий соотв. слово
Vladislav
а, ну понятно, это про API библиотеки комментарий, а не про keyword arguments
A64m
да и имплициты лучше чем эти кейворд-аргументы, хоть синтаксис обычный хаскельный будет
A64m
но в каждой второй хаскельной библиотеке для этого именно рекорды используются, подход отстойный, но хоть привычный
Vladislav
да и имплициты лучше чем эти кейворд-аргументы, хоть синтаксис обычный хаскельный будет
Имплициты это больше, чем именованные параметры, они еще передаются автоматически и неправильно.
A64m
да, больше. Это даже больше чем анонимные рекорды, которые из них можно сделать
Vladislav
Какие еще анонимные рекорды на имплицитах?
A64m
{-# LANGUAGE ImplicitParams, ConstraintKinds, GADTs, RankNTypes #-} module Main where — начинается имплементация рекордов data Rec fields where Rec :: fields => Rec fields infixr 1 ? (?) :: Rec fields -> (fields => r) -> r Rec ? e = e — готово type RXY = Rec (?x::Int, ?y::Int) xy, xy' :: RXY xy = let ?x = 1; ?y = 2 in Rec xy' = Rec where ?x = 3; ?y = 4 foo :: RXY -> Int foo r = r ? ?x + ?y type RZ = Rec (?z::Int) z :: RZ z = Rec where ?z = 42 — type RXYZ = (RXY, RZ) type RXYZ = Rec (?x::Int, ?y::Int, ?z::Int) xyz :: RXYZ xyz = xy ? z ? Rec — concatenation t1 = foo xy t2 = foo (xyz ? Rec) — subtyping t3 = foo (xy ? Rec) main = print $ foo xy
Vladislav
Эм-м-м, нет.
A64m
да
Vladislav
Как я могу принять на вход в функцию два таких рекорда с одинаково именованными полями?
Vladislav
Так я понял, там для этого ?
A64m
через разные параметры - почему нет? Их просто не сконкатенировать
Vladislav
Сейчас бы понять, к чему придраться, а то ведь придется пользоваться.
A64m
при передаче в функцию? Там ? для сабтайпинга
A64m
придраться можно для начала к отстойному выводу типов
A64m
но для анонимных рекордов это типичная проблема
Vladislav
при передаче в функцию? Там ? для сабтайпинга
Не только, я так понимаю addX :: RXY -> RXY -> Int addX a b = a? ?x + b? ?x
Vladislav
Или как еще field access делать?
A64m
да, он многоцелевой
A64m
лучше конечно для кадой его функции синоним придумать
A64m
но изобретательнаверняка очень гордился именно вот этой универсальностью
Vladislav
Для пущей универсальности вместо Rec берем Dict
A64m
да
A64m
но надо же show инстанс писать свой, для Dict это проблема будет
A64m
но такие рекорды с имплицитами, захвачеными в разные ГАДТ элементарно кастятся один к другому
Vladislav
Всё, я придумал к чему придираться буду
Vladislav
type RXYZ = Rec (?x::Int, ?y::Int, ?z::Int) type RYXZ = Rec (?y::Int, ?x::Int, ?z::Int) Типы разные, хочу одинаковые.
A64m
я писал тайпфемели, который их по алфавиту сортирует
Vladislav
Конечно Kmett предлагал, что для Constraint унификация должна быть через bi-implication
Vladislav
Может с QuantifiedConstraints теперь можно что-то придумать будет.
A64m
но со всеми этими тайплевел наворотами вся прелесть легковесности и безбиблиотечной реализации теряется, конечно
Vladislav
Мне все еще не нравится, что в данной истории можно написать foo :: RXY -> RXY -> Int foo Rec Rec = ?x и гадать, какой ?x возьмется
Зигохистоморфный
https://np.reddit.com/r/haskell/comments/7toutl/now_there_is_a_branch_to_play_with/
Vladislav
Эйзенберг мне не сказал, какая там семантика для этого, когда я его спрашивал про shadowing semantics for implicit parameters
A64m
там рассахаривание в обычный тайпкласс и тайплевел строчки, можно ни в чем себе не отказывать
Vladislav
Я понимаю во что оно рассахаривается, но там у GHC особый instance selection
Vladislav
Потому что если попробовать вот Given из reflection запихать, а потом IP, а потом сделать вот как выше foo Rec Rec = ?x, то оно разные выберет (в случае с Given первый, в случае с IP второй)
Vladislav
Это загадочно и стрёмно.
Vladislav
И наверняка от фазы Луны зависит.
Vladislav
Судя по тому, что на IP построен HasCallStack, там для шэдоунга где-то есть логика, но я почитал исходники в GHC и найти ее не смог.
Vladislav
это же тоже можно на тайплевеле запретить
Я не понял как это запретить на тайплевеле пользуясь тем фактом, что оно рассахаривается в IP
Vladislav
Мне же никто не помешает привнести два словаря для IP из разных GADT-ов
A64m
не давать пользователю конструктор, чтоб он не мог выпускать их вот так, а все обычные рекордовые операции делать как обычно делают во всяких костыльных рекордах
A64m
так останется только синтаксис конструирования рекордов через let/where
Vladislav
ага, синтаксис мечты
Vladislav
две худшие конструкции Haskell переиспользовать бы
A64m
ну лучше, чем бывает у самодельных рекордов обычно со всеми этими .=
A64m
ну и еще остается плюс, что не надо писать саму имплементацию на велью левел, только на тайплевеле туплы констрейнтов собирать, а остальное работает автомагически
Vladislav
A64m
да не всегда
Vladislav
Ну то есть если я напишу let ?x = foo ?y = bar in Rec, то оно не выведет, какие там поля в Rec, а если Rec & #x .= foo & #y .= bar, то выведет
A64m
ну да
Vladislav
А если убрать эти .=, то получится немножко короче Rec ! #x foo ! #y bar
Vladislav
что-то мне это напоминает а да, мои костыльные keyword arguments
A64m
надо в гхц протащить паттерн-синонимы-рекорды, поддерживающие лейблы, и все можно сказать что для строительства анонимных рекордов все есть
Alexander
так я хочу в серванте сделать что-то вроде: type MyAPI = "fsjkhdf" :> ReqBody (MyRequest foo) :> Post foo
Alexander
у меня есть хоть какие-то шансы на удачу?
Alexander
просто мне нужны запросы к внешнему сервису зоделать и не хочется под это 100500 урлов генерить
Alexander
при этом хочетя чтобы соотвествие request -> reply типов было
Alexander
что дает соотв GADT
Oleg
так я хочу в серванте сделать что-то вроде: type MyAPI = "fsjkhdf" :> ReqBody (MyRequest foo) :> Post foo
Возможно фигню скажу, а сфолдить тип через какую-нибуть type family для списка всех foo?
Alexander
ну я могу попытаться автоматизировать развернтку всех возможных типов, и не писать руками урлы, но или завернуть в экзестенциальную обертку, но тогда я вроде бы теряю информацию о связи
Alexander
во втором случае, я хотя бы могу сделать user facing API защищенный конечно
Denis
по куску что ты запостил непонятно что ты хочешь сделать, но решение это явно TF 😛
Alexander
не тут код генерить надо class types нужны, одних TF не хватит
Alexander
хочу url выше и data MyRequest a where R1 :: MyRequest Int R2 :: MyRequest String
Denis
ну если закрытый кайнд будет типов-вариантов(параметров для MyRequest), то можно на TF
Alexander
я когда сервер делать буду мне ж потребуется специфицировать урлы
Alexander
с TF я могу из такого типа сгенерить 1005000 урлов что нужно по закрытому кайнду
Alexander
но придется копипастить код, чтобы был и код и типы нужны классы