Переопределение функций для разных типов данных

#haskell #overriding

#haskell #переопределение

Вопрос:

Я пытаюсь определить функцию, которую я хочу вести немного по-другому в зависимости от того, какой тип данных передается в качестве аргумента, строк и целых чисел. Как бы это сделать? Или есть какие-либо изменения, которые вы могли бы предложить, чтобы каким-то образом объединить эти две функции в одну функцию. Я читал, что попытка проверки типа данных не очень похожа на haskell, поэтому я подумал, что переопределение может быть способом сделать это, но компилятору не нравится дубликат:(

 jumpTo :: Int -> [String] -> [String]
jumpTo index t = do 
    let (x,y) = splitAt index t
    init x    [last x    "QQ"]    y

jumpTo :: String -> [String] -> [String]
jumpTo string t = do 
    pos <- [fromJust (findWord string t)]
    let (x,y) = splitAt pos a
    init x    [last x    "QQ"]    y
  

Проще говоря, мне нужна функция, jumpTo которой можно передать String или Int в качестве первого аргумента; если это строка, я нахожу ее в списке, а для целого числа я сразу выполняю операции с индексом. Просто кажется более элегантным иметь одну и ту же функцию, выполняющую это.

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

1. В этом и заключается идея классов типов : learnyouahaskell.com/types-and-typeclasses он используется для «специального полиморфизма».

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

3. ну, вы определяете свой jumpTo в классе типов class JumpTo a как jumpTo :: a -> [String] -> [String] , а затем объявляете два экземпляра: instance JumpTo Int , и instance JumpTo String . Для каждого instance вы можете предоставить другую реализацию. На самом деле так show работает, например: каждый тип определяет свой конкретный способ show .

Ответ №1:

Именно в этом заключается идея классов типов: вы определяете свою функцию (или группу функций) не саму по себе, а как принадлежащую классу типов, который помечен переменной типа (или несколькими). Затем вы определяете один или несколько экземпляров класса type с различными типами, заменяющими эту переменную типа, и вы определяете отдельные тела для функции в каждом экземпляре. Конечным результатом является то, что функция имеет различное тело в зависимости от типов ее аргументов или результата.

В вашем примере:

 class JumpTo a where
    jumpTo :: a -> [String] -> [String]

instance JumpTo Int where
    jumpTo index t = do 
        let (x,y) = splitAt index t
        init x    [last x    "QQ"]    y

instance JumpTo String where
    jumpTo string t = do 
        pos <- [fromJust (findWord string t)]
        let (x,y) = splitAt pos a
        init x    [last x    "QQ"]    y
  

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

1. спасибо, теперь это имеет смысл! При компиляции я получаю недопустимое объявление экземпляра для экземпляра String, переписывание его в [] Char также не помогает. Я попробовал «обещающий» haskell, что я не буду определять какие-либо перекрывающиеся экземпляры, однако, используя функции, я получаю ошибки, выдаваемые мне, говоря, что это слишком неоднозначно. :[ как же тогда использовать String?

2. @peterxz Вам нужно будет включить TypeSynonymInstances и FlexibleInstances . Ваш написанный код по-прежнему не будет компилироваться после того, как вы это сделаете, но это не связанная с этим проблема.