объявления типа «где» - что происходит? - PullRequest
14 голосов
/ 03 октября 2011

Читая руководство QuickCheck , я наткнулся на следующий пример:

prop_RevRev xs = reverse (reverse xs) == xs
  where types = xs::[Int]

В руководстве говорится:

Свойства должны иметь мономорфные типы. «Полиморфные» свойства, такие как приведенные выше, должны быть ограничены конкретным типом, который будет использоваться для тестирования. Это удобно сделать, указав типы одного или нескольких аргументов в

где types = (x1 :: t1, x2 :: t2, ...)

пункт. Обратите внимание, что типы не являются ключевым словом; это просто локальная декларация, которая предоставляет удобное место для ограничения типов x1, x2 и т. д.

Я никогда не видел такого трюка в Хаскеле. Вот с чем у меня действительно проблемы:

  1. Почему этот синтаксис для объявлений типов вообще существует? Что это может сделать для меня, что следующее не может?

    prop_RevRev :: [Int] -> Bool
    prop_RevRev xs = reverse (reverse xs) == xs
    
  2. Является ли использование where специальным синтаксисом для объявлений типов? Или это логично (и если да, то как?)?

  3. Это стандартное использование или обычный Haskell?

Ответы [ 2 ]

14 голосов
/ 03 октября 2011

where не является специальным синтаксисом для объявлений типов.Например, это работает:

prop_RevRev :: [Int] -> Bool
prop_RevRev xs = ys == xs
  where ys = reverse (reverse xs)

и так:

prop_RevRev xs = ys == xs
  where ys = reverse (reverse xs)
        ys :: [Int]

Преимущество where type = (xs :: [Int]) над prop_RevRev :: [Int] -> Bool заключается в том, что в последнем случае вы должны указатьтип возврата, тогда как в первом случае компилятор может сделать это за вас.Это будет иметь значение, если у вас будет свойство, отличное от Boolean, например:

prop_positiveSum xs = 0 < length xs && all (0 <) xs ==> 0 < sum xs
  where types = (xs :: [Int])
4 голосов
/ 04 октября 2011

Это не специальный синтаксис, и иногда он вам просто нужен, как в следующем случае:

foo :: String -> String
foo s = show (read s)

В нынешнем виде его нельзя набирать, поскольку тип значения read s не может быть идентифицирован. Все, что известно, это то, что это должен быть экземпляр Show и Read. Но этот тип вообще не отображается в сигнатуре типа, поэтому также невозможно оставить его при этом и вывести ограниченный тип. (Просто нет переменной типа, которую можно ограничить.)

Интересно отметить, что то, что делает read s, полностью зависит от сигнатуры типа, которую каждый дает read s, например:

read "Just True" :: (Maybe Bool)

будет успешным, а

read "Just True" :: (Maybe Int)

не будет.

...