`String’ применяется к слишком большому количеству аргументов типа

#haskell #types

#haskell

Вопрос:

Я только изучаю Haskell и пытался написать простую программу для исключения первых n символов из a String . Это то, что я получил:

 cutString :: (Num n, String str) => n -> str -> str

cutString n str = case n of
        0 -> tail str
        n -> cutString (n-1) (tail str)
  

GHC выдает мне эту ошибку, и я не могу понять, почему:

 `String' is applied to too many type arguments
 In the type signature for `cutString':
 cutString :: (Num n, String str) => n -> str -> str
  

Комментарии:

1. К вашему сведению: cutString = GHC.List.drop

2. Спасибо! Я просто хотел написать свою собственную реализацию в любом случае, чтобы попрактиковаться, я только начал изучать Haskell сегодня

3. Примечание для современной аудитории: в настоящее время cutString также потребуется Eq в контексте, поскольку он использует буквальное соответствие шаблону.

4. @Ben Millwood, спасибо, что указали на это. Мне было интересно, почему этот пример больше не работает в 2021 году, даже после корректировки приведенных ниже ответов. Какой сервер (Num n, Eq n) решает проблему.

Ответ №1:

String это тип, а не класс типов, поэтому вы можете (должны) просто использовать его как есть в подписи типа.

 cutString :: Num n => n -> String -> String
  

Комментарии:

1. Эта функция, конечно, имеет еще более простой тип cutString :: Num n => n -> [a] -> [a] . Кроме того, Num в этом контексте не имеет особого смысла, поэтому, возможно, тип Integral i => i -> [a] -> [a] или даже Int -> [a] -> [a] было бы лучше.

2. @dflemstr Я уверен, что вы имеете в виду, Integer -> [a] -> [a] поскольку Int это просто довольно грубая и беспринципная оптимизация Integer 😉

3. Ну, у вас редко бывает более 536870912 элементов в списке… Если мы хотим поговорить о семантике, я бы предпочел выбрать Word / Word64 в этом случае, а затем, возможно, Natural (неотрицательный Integer ), когда базовая библиотека в конечном итоге будет содержать его.

4. Это утверждение устраняет мою путаницу в отношении использования type и type class.

Ответ №2:

Для справки, более старые GHC (т. Е. 7.2.2 или более ранние) раньше выдавали эту, скорее, более полезную ошибку:

 Type constructor `String' used as a class
In the type `(Num n, String str) => n -> str -> str'
  

Действительно, это именно ваша проблема: String это тип, и вы используете его как класс типа. Класс типа представляет собой набор типов, а не один тип, например, Integer и Double и Rational — это все типы, принадлежащие классу типа Num . Классы типов отображаются слева от => в types, где реальные типы и переменные типа отображаются справа от => .