如何在Haskell中将高阶函数应用于有效函数?

时间:2014-06-10 13:14:03

标签: haskell monads

我的功能太多了:

higherOrderPure :: (a -> b) -> c
effectful :: Monad m => (a -> m b)

我想将第一个功能应用到第二个功能:

higherOrderPure `someOp` effectful :: Monad m => m c

,其中

someOp :: Monad m => ((a -> b) -> c) -> (a -> m b) -> m c

示例:

curve :: (Double -> Double) -> Dia Any 
curve f = fromVertices $ map p2 [(x, f x) | x <- [1..100]]

func :: Double -> Either String Double
func _ = Left "Parse error" -- in other cases this func can be a useful arithmetic computation as a Right value

someOp :: ((Double -> Double) -> Dia Any) -> (Double -> Either String Double) -> Either String (Dia Any)
someOp = ???

curve `someOp` func :: Either String (Dia Any)

2 个答案:

答案 0 :(得分:23)

类型

Monad m => ((a -> b) -> c) -> (a -> m b) -> m c

没有人居住,即没有具有该类型的术语t(除非你利用分歧,例如无限递归,errorundefined等。)

遗憾的是,这意味着无法实现运算符someOp

证明

为了证明构建这样的t是不可能的,我们继续矛盾。 假设t存在类型

t :: Monad m => ((a -> b) -> c) -> (a -> m b) -> m c

现在,将c专门设为(a -> b)。我们获得了

t :: Monad m => ((a -> b) -> a -> b) -> (a -> m b) -> m (a -> b)

因此

t id :: Monad m => (a -> m b) -> m (a -> b)

然后,将monad m专门化为延续monad (* -> r) -> r

t id :: (a -> (b -> r) -> r) -> ((a -> b) -> r) -> r

进一步将r专门化为a

t id :: (a -> (b -> a) -> a) -> ((a -> b) -> a) -> a

所以,我们获得了

t id const :: ((a -> b) -> a) -> a

最后,通过Curry-Howard isomorphism,我们推断出以下是直觉主义的重言式:

((A -> B) -> A) -> A

但上面是众所周知的Peirce's law,这在直觉主义逻辑中是不可证明的。因此我们得到了一个矛盾。

结论

以上证明t不能以一般方式实施,即在任何monad中工作。在特定的monad中,这仍然是可能的。

答案 1 :(得分:5)

我认为你可以通过编写curve的monadic版本来实现你想要的东西:

curveM :: Monad m => (Double -> m Double) -> m (QDiagram B R2 Any)
curveM f = do
    let xs = [1..100]
    ys <- mapM f xs
    let pts = map p2 $ zip xs ys
    return $ fromVertices pts

这可以很容易地写得更短,但它有你想要的类型。这类似于map -> mapMzipWith -> zipWithM。函数的monadic版本必须分成不同的实现。


测试:

func1, func2 :: Double -> Either String Double
func1 x = if x < 1000 then Right x else Left "Too large"
func2 x = if x < 10   then Right x else Left "Too large"

> curveM func1
Right (_ :: QDiagram B R2 Any)
> curveM func2
Left "Too large"