В последнее время я писал код FFI, который возвращает структуру данных в монаде IO. Например:
peek p = Vec3 <$> (#peek aiVector3D, x) p
<*> (#peek aiVector3D, y) p
<*> (#peek aiVector3D, z) p
Теперь я могу представить четыре замечательных способа написать этот код, все тесно связанные:
peek p = Vec3 <$> io1 <*> io2 <*> io3
peek p = liftA3 Vec3 io1 io2 io3
peek p = return Vec3 `ap` io1 `ap` io2 `ap` io3
peek p = liftM3 Vec3 io1 io2 io3
Обратите внимание, что я спрашиваю о монадическом коде, который не требует ничего, кроме Applicative
. Каков предпочтительный способ написать этот код? Должен ли я использовать Applicative
, чтобы подчеркнуть, что делает код, или я должен использовать Monad
, потому что он может (?) Иметь оптимизации над Applicative
?
Вопрос немного усложняется тем фактом, что есть только [liftA..liftA3]
и [liftM..liftM5]
, но у меня есть несколько записей с более чем тремя или пятью членами, поэтому, если я решаю пойти с lift{A,M}
, я теряю некоторую согласованность, потому что Мне пришлось бы использовать другой метод для больших записей.