2013-06-13 3 views
8

Я пытаюсь написать простой генетический алгоритм в Haskell. Я полагал, что первый шаг должен сделать для лиц класса типов, которые являются «генетическими», например, так:Использование самых общих типов функциональных клавиш типа

class Genetic a where 
    fitness :: (Ord b) => a -> b 

Это кажется разумным мне - я не обязательно хочу ограничить фитнес-функцию типа как Float или Double, и концептуально все функции фитнеса должны сделать, это обеспечить заказ отдельных лиц.

Однако, когда я реализую этот класс типов для String обертки:

data DNA = DNA String 
instance Genetic DNA where 
    fitness (DNA s) = length s 

я вижу следующее сообщение об ошибке в GHC:

Could not deduce (b ~ Int) 
from the context (Ord b) 
    bound by the type signature for fitness :: Ord b => DNA -> b 

Разве это не то, как я должен определить функции класса типов? Должен ли я ограничивать функцию конкретным конкретным типом или предоставлять другую переменную типа конструктору типа?

+7

Это общая проблема. Ваша подпись означает, что * caller * получает выбор типа заказа, поэтому 'fitness' должен иметь возможность изготовить значение любого типа заказа и вернуть его. Примечание. «Void» (тип без значений) является упорядоченным, поэтому это невозможно. Вероятно, вы хотите параметризовать «Genetic» в пространстве порядка: 'class (Ord b) => Genetic b a, где fitness :: a -> b' – luqui

+0

@luqui Спасибо, я думаю, что понял. Пытаясь это сделать, кажется, что ваниль Haskell не любит многозначные параметры. Кто бы мог подумать. –

+1

@ DanielBuckmaster да, но расширение 'MultiParamTypeclasses' довольно распространено для использования – jozefg

ответ

13

Luqui объяснил, что проблема заключается в: fitness должен был бы быть в состоянии предоставить любойOrd экземпляр абонент может запросить, когда то, что вы действительно хотите некоторые конкретные один, который подходит тип лучший.

Это ММ очень хорошее приложение для связанных синонимов типа:

{-# LANGUAGE TypeFamilies, FlexibleInstances, FlexibleContexts #-} 

class (Ord (Fitness a)) => Genetic a where 
    type Fitness a :: * 
    fitness :: a -> Fitness a 

data DNA = DNA String 
instance Genetic DNA where 
    type Fitness DNA = Int 
    fitness (DNA s) = length s 
+0

О, ничего себе, это круто. Думаю, я мог бы пойти так. Благодаря! –

+0

Кроме того, я получаю сообщение об ошибке: 'Аргумент типа non-variable в ограничении: Ord (Fitness a)'. Он говорит: '(Использовать -XFlexibleContexts, чтобы это разрешить)' - звучит, как требуется другая прагма? –

+3

@ DanielBuckmaster, да, будьте готовы внести любое расширение, которое компилятор рекомендует в этот момент. Иногда код типа таков ... – luqui