【问题标题】:How to apply higher order function to an effectful function in Haskell?如何将高阶函数应用于 Haskell 中的有效函数?
【发布时间】:2014-06-10 13:14:03
【问题描述】:

我也有函数:

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)

【问题讨论】:

  • map p2 (x, f x) 应该做什么? map p2 暗示 p2 是一个函数,所以 (x, f x) 必须是一个列表,但它显然是一个元组。我也怀疑Dia 类型只是列表的别名,因为curve f = [...],意味着curve 返回一个列表。您可以用一个工作示例更新您的问题吗?包含p2fromVertices 的类型签名也可能会有所帮助。
  • 抱歉,错字,在 p2 之后缺少一个 [
  • 这样更容易理解发生了什么,谢谢!
  • 您使用哪个库来执行此操作?我想浏览它的文档,看看这个问题是否可以按照你想要的方式解决
  • projects.haskell.org/diagrams,但这有点无关紧要,问题更像是理论上的,示例只是为了更好地理解。

标签: haskell monads


【解决方案1】:

类型

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 -&gt; b)。我们得到

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

因此

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

然后,将单子 m 特化为延续单子 (* -&gt; r) -&gt; 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 中,这仍然是可能的。

【讨论】:

  • peirce k = k unsafeCoerce :)
  • peirce = undefined someOp = undefined FunctionToSolveWorldProblems = undefined
  • 是否有可能拥有(a -&gt; b) -&gt; c 类型的函数?你可以有这种类型的特殊版本,但从来没有这种类型本身,我想:我怎么能写一个函数,给定你喜欢的任何两种类型之间的函数,返回你喜欢的任何其他第三种类型的值?跨度>
  • @amalloy 确实,但Monad m =&gt; ((a -&gt; b) -&gt; c) -&gt; (a -&gt; m b) -&gt; m c 允许专业化。为了使论点无人居住,我们必须通过使用更高级别的类型来防止专业化,例如(forall a. b. c. (a -&gt; b) -&gt; c) -&gt; etc.
  • @amalloy 多态类型(a -&gt; b) -&gt; c 没有人居住。如果是这样,逻辑命题(A -&gt; B) -&gt; C 将是一个直觉的重言式,但它甚至不是经典的重言式。也就是说,如果A=B=TrueC=False(A -&gt; B) -&gt; C 为假。这证明不可能构造出所述多态类型的项。但是,特定实例(例如a=b=c=Int)是有人居住的。
【解决方案2】:

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

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 -&gt; mapMzipWith -&gt; 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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多