Я не совсем уверен, что вы хотите тип actuals
быть, но давайте предположим, что это [Either String (Maybe Bool)]
. В таком случае, давайте начнем с
actuals = zipWith (\ew a -> undefined) wffs assignments
где ew
является Either String Wff
и a
является Assignment
. Каким должно быть тело нашей функции? Как-то нам нужно поднять eval
в Either
. Если уступка была в Either
, мы могли бы написать liftM2 eval a ew
- но это не так. Таким образом, мы можем либо использовать return a
здесь, или применить eval
его Assignment
аргумент сначала flip
, а затем поднимите его (или многие другие возможности):
actuals = zipWith (\ew a -> liftM (flip eval a) ew) wffs assignments
Необязательно, давайте гольф дальше:
actuals = zipWith (\ew -> flip liftM ew . flip eval) wffs assignments
на мой взгляд, ни один не ясно, как
\ew a -> eval <$> ew <*> return a
где <$>
это другое название для liftM
от Control.Applicative
. Вы можете узнать больше о <$>
и <*>
в, например, «Learn вам Haskell», но в основном f <$> ma <*> mb <*> ... <*> mn
(эквивалентно liftMn f ma mb ... mn
для малых достаточно n
) является монадическая (на самом деле, applicative
) версия f a ... n
.
На этом этапе вы можете извлечь все сбои или что-то еще.Интересно, является ли присутствие Maybe
и Either
знаком, который вы могли бы немного упростить. Например, если ваш eval
может не оценить Wff, вы можете использовать Either
вместо Maybe
для записи ошибки. Тогда, ошибки будут пойманы на стадии, в которой они происходят, и успехи будут распространяться в обычном пути Either
монады:
-- eval :: Wff -> Assignment -> Either String Bool
actuals :: [Either String Bool]
actuals = zipWith (\ew a -> ew >>= flip eval a) wffs assignments
Смотрите также errors
пакет, который обеспечивает - среди его многочисленных приветственных особенностей - некоторые полезные комбинаторы, чтобы идти между Either
и Maybe
.
Я не решил проблему так, как вы предлагали, которая должна была отображаться над первым списком перед тем, как закрепить. Но вы можете сделать это, конечно, тоже:
actuals = zipWith (\ef a -> liftM ($ a) ef) (mapLift eval wffs) assignments
Здесь liftM ($ a)
является умеренно умной альтернативой ef <*> return a
.
Это кажется немного шумнее - zipWith
- это уже своего рода карта, и вы также можете воспользоваться ею.
EDIT в ответ на редактирование параметров порядка: Если вы хотите actuals :: [[Assignment]]
, то необходимые изменения просты:
actuals :: [Either String (Maybe Bool)]
actuals =
concat $ zipWith (\ew -> map (liftA2 eval ew . return)) wffs assignments
Идея здесь я снова начал с чем-то формы concat $ zipWith f wffs assignments
для неизвестного f
(concat
потому, что тип [[]]
должен быть сплющен каким-то образом ... если вы забыли его, типы не совсем совпали), а затем запросил компилятор для типа f
(путем записи where f ::(); f = undefined
и изучения полученного сообщения об ошибке), а затем написал соответствующая функция, затем эта-сниженная (в гольф). GHC 7.8 будет иметь отверстия типа, позволяющие вам получить тип неопределенного, все еще подлежащего письменному выражению, что позволяет использовать гораздо более элегантный способ разработки с использованием типов (TDD), чем это возможно сегодня (за исключением, например, Agda).
Адаптирования это использовать списковые и иметь тип [Either String Bool]
, согласно моей должности, остаются в качестве полезного упражнения :)
Вы можете добавить тип результата вы хотите – Ankur
@Ankur См редактировать –
Просто чтобы прояснить, являются типы 'Assignment' и' Assignments' должны быть одинаковыми? – Fixnum