Почему я не могу сопоставить шаблон в классе типов Haskell?

Я пытаюсь создать алгебраический тип данных Die в Haskell, определенный следующим определением:

data Die = Die6 | Die4 | Die20 | Die100

Я определил следующий класс типов

class Roll a where
  roll :: (RandomGen g) => a -> Int -> g -> ([Int], g)
  rollR :: (RandomGen g) => a -> Int -> Int -> Int -> g -> ([Int], g)

instance Roll Die where
  roll Die6 times = generateIntRandomsArray 1 6 times
  rollR Die6  times first last = generateIntRandomsArray first last times
  {--
  roll Die4 times = generateIntRandomsArray 1 4 times (mkStdGen 4)
  rollR Die4 times first last = generateIntRandomsArray first last times (mkStdGen 4)
  --}

Если я включаю в экземпляр толькоrollDie6 иrollRDie6, все в порядке, но когда я пытаюсь включить Die4, я получаю следующую ошибку:

DieRoller.hs:16:3: error:
    Conflicting definitions for ‘roll’
    Bound at: DieRoller.hs:16:3-6
              DieRoller.hs:18:3-6
   |
16 |   roll Die6 times = generateIntRandomsArray 1 6 times
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

DieRoller.hs:17:3: error:
    Conflicting definitions for ‘rollR’
    Bound at: DieRoller.hs:17:3-7
              DieRoller.hs:19:3-7
   |
17 |   rollR Die6  times first last = generateIntRandomsArray first last times
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

Я не понимаю сути. Я хочу определить различное поведение в зависимости от того, у кубика 4 или 6 сторон, но, похоже, я что-то упускаю. Вы можете помочь мне ? Спасибо . Чтобы дать вам немного больше информации, у методаgenerateIntRandomsArray есть следующее определение:

generateIntRandomsArray :: (Eq a, Random a, Num a, RandomGen g) => a -> a -> a -> g -> ([a], g)
generateIntRandomsArray start end = generate
    where generate 0 generator = ([], generator)
          generate numberElements generator =
              let (value, newGenerator) = randomR (start,end) generator
                  (restOfList, finalGenerator) = generate (numberElements-1) newGenerator
              in  (value:restOfList, finalGenerator)

Я немного скептически отношусь к необходимости использования здесь класса типов. Почему бы вам просто не определить отдельную функцию roll :: RandomGen g => Die -> Int -> g -> ([Int], g)?

leftaroundabout 01.05.2024 22:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В Haskell определения функций не могут чередоваться. Проблема в том, что вы частично определяете roll, затем определяете rollR, а затем снова возвращаетесь к roll. Вместо этого сначала сгруппируйте все определения для рулона:

roll Die6 times = ...
roll Die4 times = ...

rollR Die6 times first last = ...  
rollR Die4 times first last = ...

Большое спасибо . Это помогло мне решить проблему.

Yago 01.05.2024 19:41
Ответ принят как подходящий

Вы определяете функцию в одном «блоке», а не в нескольких блоках, поэтому:

instance Roll Die where
  roll Die4 = generateIntRandomsArray 1 4
  roll Die6 = generateIntRandomsArray 1 6
  
  rollR Die4 times first last = generateIntRandomsArray first last times
  rollR Die6  times first last = generateIntRandomsArray first last times

в противном случае вы определяете несколько функций с одним и тем же именем, что, конечно, конфликтует.

Другие вопросы по теме