我不确定你想要的类型是什么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这里使用 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
from<$>的另一个名称是哪里。您可以在例如“Learn you a Haskell”中了解更多信息,但基本上(相当于足够小)是.liftMControl.Applicative<$><*>f <$> ma <*> mb <*> ... <*> mnliftMn f ma mb ... mnnapplicativef a ... n
此时,您可以提取所有故障或其他任何内容。我想知道 theMaybe和 the的存在是否Either表明你可以稍微简化你的类型。例如,如果您eval可能无法评估 Wff,您可以使用 anEither而不是Maybe来记录错误。然后,错误将在它们发生的步骤中被捕获,成功将以Eithermonad 的通常方式传播:
-- 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已经是一种地图,您不妨利用这一事实。
编辑以响应 OP 的编辑:如果需要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是因为[[]]类型需要以某种方式展平......如果你忘记了,类型不会完全匹配),然后向编译器查询类型of f(通过编写where f :: (); f = undefined和检查生成的错误消息),然后编写适当的函数,然后进行 eta-reduced(打高尔夫球)。GHC 7.8 将有类型漏洞,允许您获得未定义的、仍有待编写的表达式的类型,从而实现比现在更优雅的类型驱动开发 (TDD) 方式(除了 Agda 等) )。
根据我的原始帖子,将其调整为使用列表推导并具有 type [Either String Bool],这是一个有用的练习:)