Что не так с моим объявлением типа quickCheck?

Я накручиваю свою собственную elem функцию под названием elem'

elem' :: (Eq a) => a -> [a] -> Bool
elem' n ys = foldl (\acc p -> if (p == n) then True else False) False ys

Кажется, работает, но я хочу быстро проверить это в GHCi, поэтому import Test.QuickCheck

verboseCheck (\a -> (\xs ->( (elem' a xs) == (elem a xs)) ) )

Без объявления типа в тестовой функции он проверяет нормально, но это потому, что он проверяет только нулевые входы.

Что-то не так с моим объявлением типа для тестовой функции:

verboseCheck (\a->(\xs->((elem' a xs)==(elem a xs))) :: Int->[Int]->Bool)
verboseCheck (\a->(\xs->((elem' a xs)==(elem a xs))) :: Char->[Char]->Bool)

Ошибка для первого:

• Couldn't match expected type ‘[Int] -> Bool’
                  with actual type ‘Bool’
    • Possible cause: ‘(==)’ is applied to too many arguments
      In the expression: ((elem' a xs) == (elem a xs))
      In the expression:
          (\ xs -> ((elem' a xs) == (elem a xs))) :: Int -> [Int] -> Bool
      In the first argument of ‘verboseCheck’, namely
        ‘(\ a
            -> (\ xs -> ((elem' a xs) == (elem a xs))) ::
                 Int -> [Int] -> Bool)’

<interactive>:258:39: error:
    • Couldn't match expected type ‘[()]’ with actual type ‘Int’
    • In the second argument of ‘elem'’, namely ‘xs’
      In the first argument of ‘(==)’, namely ‘(elem' a xs)’
      In the expression: ((elem' a xs) == (elem a xs))

<interactive>:258:54: error:
    • Couldn't match expected type ‘[()]’ with actual type ‘Int’
    • In the second argument of ‘elem’, namely ‘xs’
      In the second argument of ‘(==)’, namely ‘(elem a xs)’
      In the expression: ((elem' a xs) == (elem a xs))

person wide_eyed_pupil    schedule 26.05.2021    source источник
comment
Несвязанный: if E then True else False обычно пишется E.   -  person molbdnilo    schedule 26.05.2021
comment
какое выражение я бы переписал на E?   -  person wide_eyed_pupil    schedule 28.05.2021
comment
Ах я вижу. спасибо за объяснение, это хорошее упрощение!   -  person wide_eyed_pupil    schedule 29.05.2021


Ответы (1)


Это происходит потому, что Haskell считает, что вы ограничиваете возвращаемый тип лямбда-выражения \a->(\xs->((elem' a xs)==(elem a xs))). Это может быть легче увидеть, если вы отформатируете выражение более идиоматично:

\a -> (\xs -> ((elem' a xs) == (elem a xs)))

Для интерпретатора / компилятора это похоже на лямбда-выражение, которое возвращает другое выражение. Все хорошо.

Однако, когда вы пытаетесь аннотировать его типом:

\a -> (\xs -> ((elem' a xs) == (elem a xs))) :: Int -> [Int] -> Bool

Haskell считает, что вы аннотируете возвращаемый тип, то есть крайнюю правую часть, наиболее близкую к аннотации типа: (\xs -> ((elem' a xs) == (elem a xs))).

Заключите все лямбда-выражение в квадратные скобки перед применением типа:

(\a -> (\xs -> ((elem' a xs) == (elem a xs)))) :: Int -> [Int] -> Bool

Теперь вы можете verboseCheck это выражение:

Prelude Test.QuickCheck> verboseCheck ((\a -> (\xs -> ((elem' a xs) == (elem a xs)))) :: Int -> [Int] -> Bool)
Passed:
0
[]

Passed:
0
[]

Passed:
0
[-2,0]

Failed:
1
[2,1,-1]

Passed:
0
[2,1,-1]

Passed:
1
[]

Failed:
1
[1,-1]

Passed:
0
[1,-1]

Passed:
1
[]

Passed:
1
[-1]

Passed:
1
[1]

Passed:
1
[0,-1]

Passed:
1
[1,1]

Failed:
1
[1,0]

Passed:
0
[1,0]

Passed:
1
[]

Passed:
1
[0]

Passed:
1
[1]

Passed:
1
[0,0]

*** Failed! Falsified (after 4 tests and 2 shrinks):
1
[1,0]

Однако большинство скобок излишни, что, вероятно, и вызывает путаницу. Вы можете упростить выражения до этого:

verboseCheck ((\a xs -> elem' a xs == elem a xs) :: Int -> [Int] -> Bool)
verboseCheck ((\a xs -> elem' a xs == elem a xs) :: Char -> [Char] -> Bool)
person Mark Seemann    schedule 26.05.2021
comment
Ах! Я скопировал шаблон parens из примера моего лектора с другим функциональным тестом, адаптировав его для функции с одним аргументом, но не для функций с двойным аргументом. его пример был таким: ((\n -> (\s ->((decipher n (cipher n s)) == s))) :: Int -> [Char] -> Bool) который, очевидно, соответствует вашему шаблону после некоторых сокращений. Иногда я не уверен, где мне нужны парные скобки, а где нет, потому что я не понимаю всего порядка приоритета лямбда-выражений и других операторов. Соответствующая ссылка на учебное пособие будет большим подспорьем. - person wide_eyed_pupil; 26.05.2021
comment
@wide_eyed_pupil Если честно, я не стал их изучать. Обычно я просто добавляю или снимаю скобки, пока все не заработает. Кроме того, если вы используете hlint, он сообщит вам, есть ли у вас лишние скобки. - person Mark Seemann; 26.05.2021
comment
Если вы включите :set -XTypeApplications (в ghci) или {-# LANGUAGE TypeApplications #-} в исходном файле: verboseCheck (\a xs -> elem' @Int a xs == elem a xs). Если вы хотите указать это для elem, вместо этого вам нужно написать elem @[] @Int или elem @_ @Int. Вы можете избавиться от скобок с помощью -XBlockArguments. - person Iceland_jack; 26.05.2021
comment
Также можно аннотировать аргументы аргумента как verboseCheck: \(a :: Int) xs -> .. или \a (xs :: [Int]) -> .. - person Iceland_jack; 26.05.2021
comment
Спасибо @MarkSeemann hlint звучит неплохо. У моего лектора есть что-то в его терминале, такое, что он ведет себя как текстовый редактор, который подчеркивает парные пары, когда курсор находится рядом с ними или внутри пары, очень полезно, я думаю, он использует vim или emacs, я просто использую стандартный -стандарт (стек) GHCi. Я нашел полезную информацию о SO и в других местах о фиксированности, левоассоциативности и правоассоциативности, которая многое прояснила для меня. например, stackoverflow.com/questions/ 25589257 / - person wide_eyed_pupil; 26.05.2021
comment
Спасибо, @Iceland_jack, меня как новичка немного смущает, но полезно знать! - person wide_eyed_pupil; 26.05.2021
comment
Полиморфные функции (elem, (==)) имеют типы как невидимые аргументы, синтаксис @ позволяет передавать их явно. Когда вы пишете head "ABC", он принимает тип символа как невидимый аргумент: head @Char "ABC". Это полезно знать, но может сбивать с толку. - person Iceland_jack; 26.05.2021
comment
хорошо, теперь я понял. Спасибо - person wide_eyed_pupil; 28.05.2021