Подтвердить что ты не робот

Хаскелл: аннотация генетического алгоритма

Я новичок в мире программирования Haskell, и я режу зубы по простому генетическому алгоритму для поиска хороших решений для проблемы с Traveling Salesman. Я представляю решения как перестановки на целых числах, и поэтому у меня есть синоним этого типа

type Genome = [Int]

Сам алгоритм представляет собой набор функций, которые работают на решениях:

mutation :: Genome -> Genome
selectParents :: [Genome] -> [Genome] -> [Genome]
crossover :: Genome -> Genome -> (Genome, Genome)
selectSurvivors :: [Genome] -> [Genome] -> [Genome]

Я не уверен, насколько мой код имеет отношение к моему вопросу, поэтому, пожалуйста, спросите, нужны ли дополнительные данные. Одна вещь, о которой стоит упомянуть, заключается в том, что вышеперечисленные типы подписей фактически упрощены, я фактически использую государственную монаду для переноса StdGen, поэтому все эти функции фактически возвращают вычисления с учетом состояния.

Есть несколько вещей, которые я хотел бы сделать с этим, но не могу оторвать голову. Я хочу, чтобы можно было выбрать разные представления для решений, мне кажется, что это было бы естественным местом для использования класса типа, так что Genome будет типом класса и [Int] конкретным экземпляром этого Genome.

Теперь я хочу иметь возможность экспериментировать с реализациями, и я хочу иметь возможность использовать код в других проектах. Использование такого типа типа потребует, чтобы каждый новый алгоритм, который я создал, потребовал бы, чтобы я создал еще один экземпляр Genome, это хороший способ создать библиотеку?

Один вопрос с бонусом, просто вещь, которая беспокоила меня, - это какой-то способ создать нечто вроде синонима типа для функции, чтобы, если я пишу функцию, которая принимает функции в качестве аргументов, я могу написать синоним, а не вся сигнатура типа функции, т.е. что-то вроде следующего будет работать.

type someFunc = [Int] -> [Int] -> Int
someOtherFunc :: someFunc -> [Int] -> Int

Правильно, надеюсь, что достаточно ясное объяснение проблемы, чувствую, что я пропустил действительно очевидный ответ, но он не выскочил на меня. Приветствия

4b9b3361

Ответ 1

К сожалению, идеальное решение обычно зависит от вашей проблемной области. В этом сообщении в блоге говорится о подходе типа и побитовом подходе. Я лично считаю, что гибридный подход лучше всего, если вы хотите гибкости. Если есть хорошее побитовое сопоставление, вы можете определить его, и реализация получена из этого, в противном случае вы можете реализовать кроссовер и мутировать вручную.

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

class Genome a where
    fitness :: a -> Int
    breed :: (RandomGen g, MonadState g m) => a -> a -> m a
    mutate :: (RandomGen g, MonadState g m) => a -> m a

Затем у вас есть общие функции, которые работают с наборами геномов, независимо от реализации.

selectParents :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]
selectSurvivors :: (Genome a, RandomGen g, MonadState g m) => [a] -> m [a]

Если у вас есть хорошее сопоставление бит, вы можете просто определить фиксированные функции в BitArrays (обратите внимание, что каждый из них должен принимать функцию фитнеса в качестве параметра)

breed :: (RandomGen g, MonadState g m) => BitArray -> BitArray -> m BitArray
mutate :: (RandomGen g, MonadState g m) => BitArray -> m BitArray
selectParents :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]
selectSurvivors :: (RandomGen g, MonadState g m) => (BitArray -> Int) -> [BitArray] -> m [BitArray]

Ответ 2

Да, использование класса типа для представления генома - хороший способ. Что-то вроде этого:

class Genome a where
   mutation :: a -> a
   selectParents :: [a] -> [a] -> [a]
   crossover :: a -> a -> (a, a)
   selectSurvivors :: [a] -> [a] -> [a]
instance Genome [a] where
   mutation l = l
   selectParents l1 l2 = l1
   crossover g1 g2 = (g1,g2)
   selectSurvivors l1 l2 = l1
data Tree a = Leaf a | Branch [Tree a]   
instance Genome (Tree a) where
   mutation t = t
   selectParents l1 l2 = l1
   crossover g1 g2 = (g1,g2)
   selectSurvivors l1 l2 = l1

Что касается установки нового типа данных для каждого алгоритма, вы можете включить несколько экземпляров в свою библиотеку, но нет никаких проблем с созданием новых - что точка!