тут работает https://play.haskell.org/saved/C3xpMzcd, а вот тут https://stepik.org/lesson/7602/step/9?unit=1473 нет ошибка
Compilation error
main.hs:10:25: Not in scope: type constructor or class ‘Semigroup’
не очень понимаю, как вообще такие вопросы правильно разрешать ?
У тебя версии компилятора на степике и на play.haskell совпадают?
еслиб знал как проверить на степике, ответил бы, а так на плайграунде 9.4.8
в Playground можно выбирать до 8.4.4, но там уже был Semigroup
Кстати вопрос, если в отношении моноида, mempty задан, а в рамках Semigroup как нейтральный обрабатывается другой элемент, Это ошибка ? что то не могу сообразить..... То есть mempty отработает как нейтральный, но еще может отработать другой вход... В моем случае Maybe' Nothing
локально запускать GHC-8.2/lts-11, если можешь запустить локально
понял, могу наверное, но в случае никса, надо писать флайк...
если у тебя не никсос, то ты не обязан использовать никс
вот тут есть онлайн GHC 8.0 https://rextester.com/l/haskell_online_compiler
У меня он самый ))) Именно никсос... я даже понимаю как разого дернуть через shell нужную версию.... Это могу решить
Это ошибка по факту.....
Полугруппе не обязателен нейтральный элемент. Моноид — это как раз полугруппа с таким элементом.
не выполняются законы нейтрального элемента?
Просто моноид делается для Maybe но, Nothing должен быть нейтральным, нейтральным должен, быть Just mempty из a и когда делаю Semigroup приходиться обрабатывать Nothing
Это понятно, а что если есть два нейтральных (по сути) элементов
В первой реализации, не выполнялись, сейчас пытаюсь собрать чтоб выполнялись..
кажется, это можно 3 способами сделать, если я правльно тебя понял
да, такое тоже может быть
в математике (а точнее, в теории групп) моноид — это не тип с зафиксированным элементом и функцией, это комбинация из множества, функции и элемента. можно построить разные моноиды из одного множества и одной функции, выбирая разные нейтральные элементы
Не точно сформулировал, Nothing по условиям нельзя объявлять нейтральным, Надо mempty из a, моноид Maybe делается для Monoid a
А как такое может быть? Попробуй сложить эти нейтральные элементы: mempty1 <> mempty2. Так как mempty1 нейтральный, то выражение равно mempty2. Но раз mempty2 нейтральный, то выражение равно mempty1. Значит, mempty1 = mempty2. Или же, если это не так, то один из них не по-настоящему нейтральный.
Это понимаю, тогда возникает задача, в моем случае обработать Nothing, поскольку в операцию он ничего принести не может, получается что он будет вести себя аналогично mempty, то есть нейтральному элементу... Что похоже и не получается.... Код https://rextester.com/AMXK16979
Ну например майбе для инта, по сложению, 0 нейтрален, когда приходит Nothing можем считать только нулем по логике... Фактически возникает второе обозначение mempty
в данном случае ведет себя как нейтральный, или его можно сделать генерящим на выходе Nothing, тогда он станет каким то специальным элементом, попробую..
Да понял....
Поглощающий элемент. Как 0 в умножении.
Похоже, только вот как разрешать Поглощающий с нейтральным.... Прямо отддельно прописывать, чтоб mempty сохранил свойства по идее ?
я подумал про линзу non, которая работает в предположении, что Nothing === Just 0, но это на самом деле говорит не о другом нейтральном элементе, а о другом отношении эквивалентности/равенства
вот выше я пробовал такое без линз, не хочет или я что то не то делаю
аналогично, но не обязательно идентично
нет, линза тут для иллюстрации моих мыслей, тебе не нужны линзы в этой задаче. вообще никакого отношения
putStrLn $ show x === print x
Не обязательно. Если к моноиду добавляют поглощающий элемент, то достаточно прописать, что он поглощает всех (и слева, и справа), а оставшиеся взаимодействия оставить без изменений. Тогда поглощающий элемент будет поглощать в том числе и нейтральный, но это именно то, что и требовалось от них обоих! 0*1 = 0 и по закону 0, и по закону 1.
То есть, если специально не указано какой закон преобладает, то надо просто угадать ? Просто в кольцах я не помню какихто спец правил, в отношении "сложения" "умножения"
В том-то и дело, что никакой не преобладает, они согласованы. Если сначала назначаешь поглощающий элемент для всех, а потом нейтральный для оставшихся, они будут согласованы. Если (вдруг у тебя нет моноида) сначала назначаешь нейтральный для всех, а потом поглощающий для оставшихся, то они опять будут согласованы. Просто если у тебя есть уже моноид, то его структуру при добавлении поглощающего элемента переделывать не требуется.
mappend (Maybe' (Just mempty)) a = a — неправильный код, здесь переменная mempty создаётся и принимает что угодно. легко обнаружить эту ошибку директивой {-# OPTIONS -Wname-shadowing #-} или сразу {-# OPTIONS -Wall -Werror #-}
В кольцах две операции, а не одна. Поэтому в кольце с единицей вообще не требуется чему-то преобладать, 0 нейтрален по (+), 1 нейтральна по (*). Вот для полей, когда требуется нахождение обратного элемента, уже говорят, что X\{0} должен быть группой по 1.
Это когда две операции, или моноид с поглощающим.... Я похоже пока уткнулся, в нахождение mempty при сопоставлении с образцом....
Понял, кольца помнил, поля уже не очень..
Потому что это и не требуется. Если ты добавляешь к моноиду элемент, и назначаешь его новым нейтральным, то сопостовлять со старым mempty не требуется, ведь новый нейтральный будет нейтрален ко всем. Если добавляешь поглощающий, то сопоставлять с нейтральным тоже не требуется, ведь поглощающий и так поглощает всех, а нейтральный остаётся нейтральным.
Есть некий Monoid a Мне нужен Monoid (Maybe' a) where newtype Maybe' a = Maybe' { getMaybe :: Maybe a } deriving (Eq,Show) instance Monoid a => Monoid (Maybe' a) where mempty = Maybe' (Just mempty) mappend (Maybe' (Just a)) (Maybe' (Just b)) = Maybe' (Just (mappend a b)) mappend (Maybe' Nothing) a = a mappend a (Maybe' Nothing) = a вот такое как мне кажеться должно работать, поскольку все Just и так обработаются первым случаем, а обработка Nothing приравнивает его по результатам к mempty базогого типа Но степик дает ответ Wrong answer вроде все проверил, чтоб работало 2 Nothing хотя бы одному надо указать тип, что разумно и добавить mappend (Maybe' Nothing) (Maybe' Nothing) = Maybe' (Just (mempty :: a)) но вот тут указать что mempty типа a, а без ссылки на тип не понятно что вернуть...
У вас инстанс не удовлетворяет законам. Заметьте: вы пишете, что mempty = Maybe' (Just mempty), но из mappend a (Maybe' Nothing) = a следует, что mempty <> Maybe' Nothing = mempty, а не Maybe' Nothing. По вашему mappend нейтрален всё-таки Maybe' Nothing. Как мы говорили, если хотите сохранить старый нейтральный элемент, новый должен не сохранять другие (как у вас), а поглощать их.
Формально, я не могу сделать Nothing нейтральным, по условиям задачи, могу написать, что вернет результат, аналогичный mempty, это не запрещено вроде...
Да и в этом проблема, я не понимаю как поймать в сопоставлении с образцом (Just mempty)
попробую с поглощением
Ещё раз, зачем? Вы не сможете просто добавить, что Nothing <> Just mempty = Nothing, а для остальных оставить Nothing <> Just a = Just a. Nothing должен поглощать вообще все (NB!!!!!!!!!!!) элементы. Как выглядит уравнение для поглащающего всех!!!!!!!! Maybe' Nothing? Есть ли в нём хоть слово про Maybe' (Just mempty)?
Понял, то есть ответ, если Nothing не нейтрален - то он обязан быть поглощающим ? я правильно понял?
с этим еще не разбирался, но похоже проблема там есть, судя по тому что говорит михаил, или по тому как я его понимаю..
для этого и нужен квикчек, чтобы опираться на факты, а не на какое-то неточное понимание
Да понятно надо разобраться с ним.... В данном случае было скорее непонимание, того что если Nothing не нейтрален, то он обязан быть поглощающим....
Это следует из ассоциативности и невозможности различать элементы старого моноида. Если б на нём было ещё равенство, то ваше добавление "поднейтрального" элемента (сохраняемого нейтральным, но сохраняющего все прочие), стало бы возможно.
Там было EQ, но только в Определении типа для которого строился моноид.... Подозреваю, что этого может быть достаточно, но пока не соображу как...
Речь об Eq не просто для одного типа, а об Eq в контексте инстанса. А по заданию его там нет и не требуется.
просто там инстансе делался для типа Maybe' a у которого есть deriving (Show,Eq) но вот как связываються классы наследуемые с инстансом ддля типа я не очень понимаю..
Автоматический вывод Eq не означает, что новый тип всегда будет с равенством. В Maybe' a будет равенство, только если оно есть в a.
deriving
А что бы почитать по квикчек ? в смысле я вот написал, https://play.haskell.org/saved/VeBicyG6 думаю работает, хорошо бы обвязать тестами, Вопрос как это правильно делать
deriving — это автоматическая реализация инстанса по содержимому типа
То есть - некий тип, реализует этот инстансе. То есть соотвествует классу типов. (это я назвал наследованием, хотя корректнее реализация интерфейса)
только deriving newtype похож на наследование, хотя это тоже не наследование
да, реализация интерфейса — корректнее, но всё ещё неточно. потому что инстанс может быть не у типа, а у некоторой хитрой комбинации типов (а также и без типов вообще, но это вырожденный случай, почти никогда не применяющийся)
Это пока не очень понимаю, думаю позже.... Просто мне казалось, что дерайвинг или инстансе EQ например - по результату одно и тоже, если меня устравивает базовая реализация EQ, EQ плохйо пример, лучше Show - позволяет больше реализаций
deriving означает «компилятор, напиши инстанс за меня»
Да я так и понимал. Называть наследованием не стоит, постараюсь запомнить
можно начать с функции quickCheck, запустить её вот так: associativity :: (Eq a, Monoid a, Show a) => a -> a -> a -> Property associativity x y z = (x `mappend` y) `mappend` z === x `mappend` (y `mappend` z) quickCheck $ associativity @String
или вот введение https://www.seas.upenn.edu/~cis1940/fall16/lectures/10-testing.html
Это понял, спасибо у меня скорее вопрос про такое например lookup :: Ord k => k -> m k v -> Maybe v к такой функции, я еслиб писал руками тесты, то писал что то типа ls = x : filter (/=x) xxs assert lookup x ls == Just x assert lookup x ls2 == Nothing
а вот ещё я себя бесстыдно порекламирую https://www.youtube.com/watch?v=lL4cA5hcSP0&list=PLL7ZEYyg9KfkZfgWYqpwbokHc4Hezc3C6&index=4&t=841
смотрю, пока не дошел, до составления инстансе Arbitrary, вот только не понимаю пока как, двух параметрический тип, второй параметр, по функциям не важен..... пытался написать такое но неверно prop_finded :: (Ord k, ListMap k l) => k -> l -> Property prop_finded x lM = x == k where (k,v ) = fromJust lookup x lm похоже, не понимаю чего то.... Образцов не нашел.... вот код, как мне кажеться тут нужна Arbitrary https://play.haskell.org/saved/xWpb0JjZ
в данном случае можно "наследовать" newtype ListMap k v = ListMap{getListMap :: [(k, v)]} deriving newtype (Arbitrary) deriving stock (Eq, Show)
В данном, поскольку он собран из примитивов ?
нет, поскольку это обёртка, (почти) не меняющая смысл оборачиваемого
по сути это тогда верно для любого newtype ?
У мап обычно есть какие-то требования к ключам, например с таким дерайвингом не выполняется lookup k (delete k m) == Nothing
Это то как раз выполняется, или я чего то не поонимаю, https://play.haskell.org/saved/I4sJ1Tlf влоб такое не тестировал, но должно работать, во всяком случае по требованиям реализации
А еслиб не подходил, как бы могла примерно выглядеть реализация инстансе ?
выполняется, если delete правильно реализовать
Или инсерт как делит+конс
если мы не паримся о дублировании ключей, то чтобы сгенерить случайный список пар, надо сгенерить пару много раз и собрать результаты в список (рекурсивным консом, например)
Это понятно, Про много ключей паримся, не должно быть... не понятен синтаксис, я на нем постоянно ошибаюсь.
и еще мне казалось это должно работать, но не работает sample ( ListMap @Int @String) расширение про DerivingStrategies включил, тогда прошло множественное наследование, а вот вывести что там за варианты генеряться пока не получается.... Причем не понимаю что не так.... Main.hs:10:12: error: • Couldn't match expected type: Gen a0 with actual type: [(Int, String)] -> ListMap Int String • Probable cause: ‘ListMap’ is applied to too few arguments In the first argument of ‘sample’, namely ‘(ListMap @Int @String)’ мне казалось что после дерайвинг, должен быть генератор, определен... Но судя по ошибке, я им как то не так пользуюсь...
синтаксис чего именно?
посмотри в репле :type ListMap @Int @String
понял, возиться в плаграунде не стоит, наверное привыкну...
после deriving Arbitrary можно пользоваться генератором arbitrary :: Gen a
ну и зачем ты запихиваешь это в sample?
первая идея была написать arbitrary ListMap, но это не прошло, мне кажеться, что раз появился инстансе, то к нему можно обратиться, но поскольку нельзя генерить примеры, без типов внутренних, предположил что надо их задать.... Я вижу что не понимаю, как этим пользоваться, но пока не понимаю. чего не понимаю.
хотел посмотреть варианты генерации
ок, это уже понятная задача > :t arbitrary arbitrary :: forall a. Arbitrary a => Gen a вот генератор чего угодно но я хочу конкретный генератор, например, для Int. arbitrary принимает тип как параметр, можно его задать > :t arbitrary @Int arbitrary @Int :: Gen Int ура, получился конкретный генератор но как из него достать значения? поищем в документации функцию, принимающую Gen. наш лось: > :i generate generate :: forall a. Gen a -> IO a -- Defined in ‘Test.QuickCheck.Gen’ она принимает Gen, а у нас есть Gen. соединяем > :t generate $ arbitrary @Int generate $ arbitrary @Int :: IO Int типы сошлись, получилось действие IO с Int на выходе. отлично, мы знаем, как такие штуки запускать > generate $ arbitrary @Int 30 > generate $ arbitrary @Int 25 > generate $ arbitrary @Int 11 работает!
из этой логики получается generate $ arbitrary @ListMap понял, пробую
Не очень понял, компилятор сказал app/Trys.hs:43:1: error: Illegal use of multiple, consecutive deriving clauses Use DerivingStrategies to allow this нелегальное использование нескольких, последовательных .... я включил расширение, заработало.... Некоректно назвал.... множественными
это множественное, но не наследование
вот так смог добиться чтоб работало, но завернут в дополнительный тип, как избежать не понимаю newtype Lis = Lis (ListMap Int String) deriving newtype (Arbitrary) deriving stock (Eq,Show) и тогда выдает результаты generate $ arbitrary @Lis Lis (ListMap {getListMap = [(-2,"\DLE\39678lC%E\1087200\1045603\1036824(Nd"),(-23,"m\1062203o\1066152g{\CANP\SOPIKA"),(2,"w!\EM\\\CAN\199018\"\205299\DC26\985972\190974"),(20,"\1027422wQ\111025V далее обрезал, не значимо
удали тип Lis. какая будет ошибка?
Понял, тупил, спасибо
вот новый вопрос, вот такой код prop_all_ok :: ( Eq a, Ord a, Show a,Eq b, Show b) => (a,b) -> ListMap a b -> Property prop_all_ok (key,val) lm = conjoin [ln,lj,d,i] where ln = lookup key (delete key lm) === Nothing lj = lookup key (insert key val lm) === Just val d = delete key lm === ListMap ( filter (\(k,_) -> k /= key) (getListMap lm)) i = insert key val (delete key lm) === insert key val lm вызываю его так labelledExamplesResult $ (prop_all_ok @(Int, String) @(ListMap Int String)) Вроде работает, показывает что 100 тест ок.... но возникает вопрос правильности теста.... Хотябы на втой взгляд и куад покопать еще ? В смысле какие еще проверки стоит сделать ?
у тебя тут a = (Int, String), b = ListMap Int String; но думаю, что ты хотел a = Int, b = String
свойство d странное. нет смысла в тесте копировать реализацию
остальные свойства хорошо прописаны, всё правильно
можно ещё проверить свойства пустого словарика. чтение любого ключа из пустого даёт Nothing, удаление из пустого даёт пустой
я и спрашивал, как бы проверить, не копируя...
Так там в данных в листах точно есть пустые, или отдельным проп ом?
понял, спасибо, ступил...
отдельно. потому что свойство «поиск чего угодно заканчивается Nothing» не работает для любого словаря, только для пустого
ну не надо себя унижать, в тех трёх как раз всё по умному написано, прямо здорово
Так и говорю, что когда подумал про этот, не придумал например такого d = delete key (insert key val lm) === delete key lm
лучше свойствам более осмысленные имена давать
вот смотри написал такое prop_with_empty :: Int -> Property prop_with_empty key = conjoin [l,d] where l = lookup key (empty :: ListMap Int String) === Nothing d = delete key (empty :: ListMap Int String) === (empty :: ListMap Int String) запускаю, вроде осмысленно labelledExamplesResult $ (prop_with_empty @Int ) и ошибка app/Trys.hs:17:29: error: [GHC-95781] • Cannot apply expression of type ‘Int -> Property’ to a visible type argument ‘Int’
просто прочитай и переведи сообщение об ошибке
нельзя подставить значение в параметр, если нет параметра. без пруда не вытащишь и рыбку из него
Так есть же.... prop_with_empty key =
это параметр на уровне значений, а ты пытаешься передать Int на уровне типов
ну по аналогии с ассоциативити
Мне же надо как то указать, что генерировать надо инты, на вход функции
так ты указал уже :: Int -> Property
рассмотрим f :: forall a. a -> P f x = _ g :: Int -> P g x = _ у первой функции параметры (a :: Type) и (x :: a) у второй — (x :: Int) в первую можно подставить (Int :: Type) (1 :: Int) или (Char :: Type) ('a' :: Char) во вторую можно подставить (2 :: Int), подставить Int некуда, просто нет дырки для этого
Обсуждают сегодня