Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jun3/haskell: fix questions and add some new #341

Merged
merged 6 commits into from
Mar 24, 2022
Merged

Conversation

antonkalinin-ml
Copy link
Contributor

@antonkalinin-ml antonkalinin-ml commented Dec 20, 2021

Некоторые исправления, которые обсуждали во время моей сдачи, они описаны в #309.

Про синонимы стратегий вычисления лень было думать. Это надо источники перечитывать и думать, что выпилить, что оставить, как сформулировать вопросы. Может, потом :).

Про irrefutable patterns в let/where на верхнем уровне добавлять не стал, у нас эта тема есть на мидле, так что внесу туда.

@@ -127,7 +127,7 @@
* `ScopedTypeVariables`
* What is the main goal of this extension?
* Higher ranked types
* What is a "rank" of a function?
* What is a higher rank function?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вопрос "как определяется ранг функции", на мой взгляд - вполне корректный и не нуждается в удалении. Можно пояснить, почему он заменяется на "что такое функция высшего ранга"? Это более слабый вопрос, поскольку в нём не уточняется, например, чем именно отличается функция 2-го ранга от функции 3-го.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Чтобы определять числовой ранг функции, у нас не хватает источника. В доках по хаскелю не объяснено, как по сигнатуре определить ранг.

Стас говорил, что определение ранга непростое, и мы подумали, что оно на практике не нужно. Достаточно отличать первый ранг от всех остальных, а уж какой он - третий или четвертый - не влияет на то, как применять RankNTypes.

* What is the function `seq` (and operator `$!`)?
* What is the function `deepseq` (and operator `$!!`)?
* Could using `seq` change the returned value of the function?
* What is the expression result: ``(a + b) `seq` ((a + b) : list)``? Why?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не очень понятно к чему относится второй вопрос Why?, может его раскрыть?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вопрос, почему результат именно такой, какой он есть :). Why does it happen? - может так?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it?

Copy link
Contributor

@evgeny-osipenko evgeny-osipenko Dec 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Грамматическая придирка - в текущем виде, кодовая цитата относится к слову "result", то есть вопрос буквально звучит как "Какой у выражения результат: (a+b) `seq` ((a+b) : list)". Я думаю, будет более верно сформулировать как "What is the result of the expression: <>".

А вообще, мне не совсем понятно, что именно ожидается в ответе на этот вопрос - ну, результатом будет (a+b) `seq` ((a+b) : list), duh. Ну, можно переписать это как let x = a+b in x `seq` (x:list) Может, лучше вообще спрашивать не про "результат", а про поведение в конкретных ситуациях - под evaluate и evaluateNF, если в a боттом, если в a стоит trace или unsafePerformIO, если на результат ещё сверху повесили trace или unsafePerformIO, и продвинутый вопрос - если мы в реализации (+) впишем trace или unsafePerformIO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С придиркой согласен, переделаю.

Насчет ответа на вопрос: да, здесь вопрос скорее о поведении, а не о результате - что в этом выражении seq бесполезен, и надо объяснить почему. Кстати, источника не хватает.

а про поведение в конкретных ситуациях - под evaluate и evaluateNF, если в a боттом, если в a стоит trace или unsafePerformIO, если на результат ещё сверху повесили trace или unsafePerformIO, и продвинутый вопрос - если мы в реализации (+) впишем trace или unsafePerformIO.

Про evaluate не понял. Про unsafePerformIO пусть отвечающий рассказывает в вопросе про то, может ли seq изменить результат выражения :). Там прямо напрашивается. Или можно явно спросить об этом, но мне кажется, изначальный смысл вопроса был в другом.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поправил вопрос, но так и не нашел источник, где я видел ответ. Может, потом. Вы знаете ответ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если referential transparency соблюдается - то выражение семантически эквивалентно let x = a+b in x `seq` (x:list). По факту - компилятор имеет полное право как объединить одинаковые выражения, так и оставить их раздельными.

let a = unsafePerformIO (print "A" >> pure 1)
let b = 2
let z = (a + b) `seq` ((a + b) : list)
print "Start"
zh : _ <- evaluate z
print "Mid"
void (evaluate zh)
print zh
print "End"

На код выше компилятор может написать как Start // A // Mid // A // 3 // End, так и Start // A // Mid // 3 // End - допустимы оба варианта. Скорее всего, GHC будет работать по первому с -O0 и по второму с -O2.

@evgeny-osipenko
Copy link
Contributor

evgeny-osipenko commented Dec 23, 2021

Кстати о трейсе, как вам такое предложение - перенести весь блок "Debugging" перед "Laziness", и в блоке про ленивость добавить задачек с использованием трейса, например:

let a = trace "a" (trace "head a" 10 : trace "tail a" [])
let b = trace "b" (Just (trace "fromJust b" 20))
let c = trace "c" (trace "c1" () `seq` trace "c2" ())
let d = trace "d" (Just (trace "d1" () `seq` trace "d2" ()))
let e = trace "e" (let !e1 = trace "e1" () in trace "e2" ())
let f = trace "f" (let Just !f2 = trace "f1" (Just (trace "f2" (Right (trace "f3" ())))) in trace "f4" (Just (trace "f5" f2)))
-- Assuming a..f were never evaluated before, what would `void (evaluate a)` print?
-- What would `void (evaluateNF a)` print?
-- Among the lines printed, are there any restrictions on their order of appearance?

@antonkalinin-ml
Copy link
Contributor Author

antonkalinin-ml commented Dec 23, 2021

Кстати о трейсе, как вам такое предложение - перенести весь блок "Debugging" перед "Laziness", и в блоке про ленивость добавить задачек с использованием трейса, например:

let a = trace "a" (trace "head a" 10 : trace "tail a" [])
let b = trace "b" (Just (trace "fromJust b" 20))
let c = trace "c" (trace "c1" () `seq` trace "c2" ())
let d = trace "d" (Just (trace "d1" () `seq` trace "d2" ())
let e = trace "e" (let !e1 = trace "e1" () in trace "e2" ())
let f = trace "f" (let Just !f2 = trace "f1" (Just (trace "f2" (Right (trace "f3" ())))) in trace "f4" (Just (trace "f5" f2)))
-- Assuming a..f were never evaluated before, what would `void (evaluate a)` print?
-- What would `void (evaluateNF a)` print?
-- Among the lines printed, are there any restrictions on their order of appearance?

Можно. А зачем столько строк, если используется только первая? Если это подвох, то хватило бы и двух строк.

@evgeny-osipenko
Copy link
Contributor

evgeny-osipenko commented Dec 24, 2021

А зачем столько строк, если используется только первая?

Все три вопроса повторяются для каждой строки.

@stanislav-az
Copy link
Contributor

добавить задачек с использованием трейса

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

@antonkalinin-ml
Copy link
Contributor Author

А зачем столько строк, если используется только первая?

Все три вопроса повторяются для каждой строки.

Слишком много упражнений, некоторые сложно прочитать, лень будет над ними думать. Так как ответ элементарно узнать в репле, это рискует быть самым популярным способом решения :). Достаточно по одному примеру на каждое маленькое знание, наличие которого мы хотим проверить. По-моему, и первой строки хватило бы, на понимание ленивого вычисления в целом. Многие вещи мы уже спрашиваем в других вопросах - про bang patterns в let, про seq.

@antonkalinin-ml
Copy link
Contributor Author

Детально по примерам:

let a = trace "a" (trace "head a" 10 : trace "tail a" [])

Согласен, на понимание ленивых вычислений годится.

let b = trace "b" (Just (trace "fromJust b" 20))

В принципе то же самое, только с Maybe вместо списка, думаю, что избыточно.

let c = trace "c" (trace "c1" () seq trace "c2" ())

Вопрос на понимание seq, который мы уже спрашиваем, но здесь надо знать один нюанс, про порядок вычисления параметров seq. Можно добавить вместе с источником про порядок вычислений в seq.

let d = trace "d" (Just (trace "d1" () seq trace "d2" ()))

Ленивые вычисления (первый пример) + seq, избыточно.

let e = trace "e" (let !e1 = trace "e1" () in trace "e2" ())

Bang patterns in let - про это уже есть вопрос, избыточно.

let f = trace "f" (let Just !f2 = trace "f1" (Just (trace "f2" (Right (trace "f3" ())))) in trace "f4" (Just (trace "f5" f2)))

Ленивые вычисления + bang pattern in let, избыточно и уж очень сложно прочитать.

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

Если хочется именно задачки, на прокачку навыков предсказания работы ленивых вычислений (только зачем? Кажется, это не особо нужный навык), то мне кажется, надо что-то поинтереснее (только как тут сделать интереснее? :)). Последний пример, с 4 уровнями скобок, я даже и не пытался понять.

@antonkalinin-ml
Copy link
Contributor Author

Идею про упражнения я вынес в issue #357 , не хочется добавлять их в этот ПР, а то он еще полгода не смержится. Внес некоторые финальные правки, посмотрите пожалуйста.

@stanislav-az stanislav-az merged commit 1e13742 into master Mar 24, 2022
@stanislav-az stanislav-az deleted the jun3-haskell-fixes branch March 24, 2022 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants