Безточечная конвертация

У меня есть некоторые функции перемещения/доступа для работы с моим типом сетки:

cell :: Mesh a -> Int -> Maybe (Cell a)
neighbour :: Mesh a -> Int -> Cell a -> Maybe (Cell a)
owner :: Mesh a -> Cell a -> Maybe (Cell a)

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

type MMesh a b = MaybeT (State (Mesh a)) b

Итак, у меня есть такие монадические аксессоры:

getMesh = get :: MMesh a (Mesh a) -- just to remove type declarations

cellM id = getMesh >>= (MaybeT . return) <$> (\m -> cell m id)
neighbourM idx cell = getMesh >>= (MaybeT . return) <$> (\m -> neighbour m idx cell)
ownerM cell = getMesh >>= (MaybeT . return) <$> (\m -> owner m cell)

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

cellM = liftMesh cell
neighbourM = liftMesh neighbour
ownerM - liftMesh owner

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

Upd: добавление полного текста сюда: http://pastebin.com/nmJVNx93


person Alexander Yushkov    schedule 06.09.2015    source источник
comment
Пожалуйста, сделайте свой код автономным. В частности, добавьте операторы импорта и определения для Mesh, Cell и т. д. Людям будет проще убедиться, что их бесточечные версии проверяются на тип.   -  person jub0bs    schedule 06.09.2015
comment
Вы пробовали инструмент pointfree?   -  person n. 1.8e9-where's-my-share m.    schedule 06.09.2015
comment
Спасибо за идею, но кажется, что это слишком сложно для бесточечного инструмента или я что-то не так делаю   -  person Alexander Yushkov    schedule 06.09.2015


Ответы (1)


Просто используйте gets , который возвращает проекцию состояния, заданного на него произвольной функцией, и MaybeT:

cellM ix = MaybeT (gets (\m -> cell m ix))

neighbourM ix c = MaybeT (gets (\m -> neighbour m ix c))

owner c = MaybeT (gets (\m -> owner m c))

(Примечание: я рекомендую не называть вещи id. Стандартная функция id слишком важна, что приводит к путанице в именах.)

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

cell :: Int -> Mesh a -> Maybe (Cell a)

cellM ix = MaybeT (gets (cell ix))

(Вы могли бы дойти до конца и вместо этого написать cellM = MaybeT . gets . cell, но я чувствую, что это будет чрезмерно скрывать то, что делает cellM.)

P.S.: Учитывая, что вы используете State, скорее всего, вас также интересуют функции, изменяющие сетку. Однако, если нет, Reader будет более подходящим, чем State.

person duplode    schedule 06.09.2015
comment
Однако изменение порядка аргументов может оказаться невозможным. - person jub0bs; 06.09.2015
comment
@Jubobs Если это не так, то не надо :) (Или используйте flip, но мне действительно не хочется добавлять это к ответу. Это становится некрасиво ...) - person duplode; 06.09.2015
comment
Да, быстро портится. Я просто придирался. - person jub0bs; 06.09.2015
comment
Внезапно cell и другие возвращают Maybe (Cell a), который обрабатывается преобразователем MaybeT, поэтому применение приводит к результату join $ (MaybeT . return) <$> gets (\m -> cell m id), что ненамного лучше. - person Alexander Yushkov; 07.09.2015
comment
@AlexanderYushkov Вам нужно только MaybeT (gets (\m -> cell m ix)). Тип MaybeTm (Maybe a) -> MaybeT m a, поэтому он может выполнить нужное преобразование самостоятельно. - person duplode; 07.09.2015
comment
Вау, спасибо, это действительно работает так, как задумано. Так что проблема действительно была не в безточечной конвертации, а в правильном использовании библиотек. - person Alexander Yushkov; 07.09.2015