如何在Haskell中实现这个函数

8

Haskell 的一个美妙之处在于:函数的类型几乎决定了它的实现方式。但是对于这个函数,我的大脑似乎无法理解嵌套的函数语法:

mkDyn :: (Typeable a) => ((a -> IO()) -> IO ()) -> ((Dynamic -> IO()) -> IO ())

唯一的问题是如何处理 fromDynamic 调用中所需的错误处理,但是...一旦我弄清楚了其他事情,我就可以处理它。我猜需要在某个地方添加以下内容。但我似乎无法弄清楚包装器 lambda 的东西。
case fromDynamic x of
  Just x -> f x
  Nothing -> undefined -- TODO 

1
哇,我甚至不知道 Haskell 有动态类型支持,更不用说它在 base 中可用了。每天都会学到新东西。 - Joey Adams
@Joey 如果我没记错的话,甚至有一个库可以使用简单的赋值运算符编写命令式风格的代码,但我忘了在哪里看到过。我想它曾经在 Planet Haskell 上提到过。 - fuz
2个回答

10

我认为您想要使用toDyn,而不是fromDynamic。所以让我们慢慢来:

mkDyn :: Typeable a =>
         ((a -> IO ()) -> IO ())
      -> (Dynamic -> IO ())
      -> IO ()
mkDyn k f = ...

我们的返回类型应该是IO(),我们可以通过调用kf来获得它。调用f对我们帮助不大,因为我们会以某种方式实现一个Dynamic,但我们不能从k(可靠地)这样做。所以我们想要调用kk需要另一个函数作为其参数,因此让我们这样开始:

mkDyn k f = k (\a -> ...)

所以函数的参数是 Typeable a => a -> IO ()。我们没有这种类型的函数,但我们有一个类型为Dynamic -> IO ()的函数。由于Typeable限制,我们可以使用toDyn将我们的a转换为Dynamic,得到:

mkDyn k f = k (\a -> f (toDyn a))

有更简单的实现方式(例如return ()k (\a -> return ())),但这个看起来更有意义。


3
@rampion 两个人都可以玩这个游戏! mkDyn = (. (. toDyn)) 可以翻译为“创建动态类型 = (. (. toDyn))”。 - Daniel Wagner
2
我倾向于使用带点的版本。只有在事情真的只是一个简单的管道时,我才会使用无点风格。任何稍微复杂一点的东西,下次阅读代码时我都会后悔。 - nominolo
@Daniel Wagner 使用函数组合的部分,两次?我想我的大脑刚刚有点爆炸了。 - Dan Burton
我喜欢stackoverflow,特别是Haskell问题。太棒了,谢谢! - mentics

5

我作弊了,使用了Djinn程序

我首先推广了给定的类型:

f :: (a -> c)
  -> ((a -> b) -> b)
  -> ((c -> b) -> b)

(a -> c) 代表 toDyn 函数c 代表 Dynamicb 代表 IO ()

Djinn 的结果出人意料地简单:

@djinn (a -> c) -> ((a -> b) -> b) -> ((c -> b) -> b)
f a b c = b (\ d -> c (a d))

通过使用toDyn函数来使其更加具体化(替换(a -> c)),我们得到:

mkDyn :: (Typeable a) => ((a -> IO()) -> IO ()) -> ((Dynamic -> IO()) -> IO ())
mkDyn b c = b (\ d -> c (toDyn d))

这与nominolo的答案相匹配。


1
这证明了 nominolo 是一个 djinn 吗? - Landei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接