Этот вопрос не субъективен. В упомянутой книге используется очень специфический глагол, и я хотел бы понять, каково значение этой фразы, потому что, боюсь, я что-то неправильно понимаю.
Из « Learn You a Haskell» следующий абзац третий и последний содержит «мы предполагаем *
».
data Barry t k p = Barry { yabba :: p, dabba :: t k }
И теперь мы хотим сделать это примером
Functor
.Functor
хочет типа,* -> *
ноBarry
не выглядит так, как у него Что это за видBarry
? Ну, мы видим, что он принимает три параметра типа, так что будетsomething -> something -> something -> *
. Можно с уверенностью сказать, чтоp
это конкретный тип и, следовательно, имеет своего рода*
. Ибоk
, как мы предполагаем,*
и так по расширению,t
имеет вид* -> *
. Теперь давайте просто заменим эти типы наsomething
s, которые мы использовали в качестве заполнителей, и мы увидим, что они имеют вид(* -> *) -> * -> * -> *
.
Почему мы вообще что-то предполагаем? После прочтения «мы предполагаем, что X (то есть мы предполагаем, что X истинно)», для меня естественно думать, что мы должны также рассмотреть случай, когда X ложно. В конкретном случае примера не может t
быть добрым (* -> *) -> *
и k
добрым (* -> *)
? Если бы это было так, то все , что t
и на k
самом деле были, по- t k
прежнему будет тип бетона, нет?
Я вижу, что вся цепочка рассуждений затем проверяется с помощью компилятора, но я не думаю, что компилятор предполагает . Если это произойдет, я хотел бы знать, что, если это не так, то, опять же, я боюсь, что мне не хватает значения параграфа.
k :: L
для любого видаL
, покаt :: L -> *
. Компилятор здесь, однако, должен выбрать какой-то конкретныйL
тип или прибегнуть к поликинду. Поликинд был бы наиболее общим вариантом, но здесь GHC выбираетL = *
(базовый Haskell не имеет поликиндов, они должны быть включены как расширение). Поскольку он выбирает что-то довольно произвольное, LYAH использует слово «предположить» (AFAICT).Ответы:
На самом деле, компилятор предполагает! Но вы можете попросить об этом не с расширением PolyKinds. Подробнее об этом можно прочитать здесь . С этим расширением вид
Barry
будетforall k. (k -> *) -> k -> * -> *
.источник
Хорошая точка зрения. Автор делает ненужное предположение. Возможно, просто для того, чтобы облегчить понимание в его главе Type Foo, но такие люди, как вы, могут справедливо усомниться в этом.
Оба
t
,k
иp
являются переменными типа. Как мы видим из этого,yabba :: p
он может жить один, поэтому он похож на константу, как если бы это было значение вместо типа, его сигнатура типа сказала быInt
илиChar
, как угодно ... вы называете это. Но так как это тип, то это и есть подпись*
.Однако
t
тип здесь принимает переменную типаk
для создания type (dabba :: t k
),поэтому мы уверены, что (здесь нет предположений).t
имеет такую же сигнатуру типа, как* -> *
иk
имеет*
Как только мы узнаем это ... типовая
Barry t k p
сигнатура типа(* -> *) -> * -> * -> *
означает, что она принимаетt
тоk
и другоеp
и дает намBarry
тип.Редактировать Не забудьте прочитать комментарий @ luqui ниже.
источник
k
не обязан быть таким,*
каким вы утверждаете, что это при выводеt
. Мы могли быk :: * -> *
иt :: (* -> *) -> *
, например. Добавьте полеdoo :: k Int
к записи, и оно пройдет без проблем.