还有什么可以`loeb`功能用于?

时间:2014-03-16 17:07:58

标签: haskell functor curry-howard

我正在努力理解"Löb and möb: strange loops in Haskell",但是现在我的意思正在逐渐消失,我只是不明白为什么它会有用。只是召回函数loeb定义为

loeb :: Functor f => f (f a -> a) -> f a
loeb x = go where go = fmap ($ go) x

或等效地:

loeb x = go 
  where go = fmap (\z -> z go) x

在文章中有一个带有[]仿函数和电子表格实现的示例,但对于我来说,就像电子表格本身一样(从未使用它们)对我来说有点陌生。

虽然我理解电子表格的内容,但我认为尽管有列表,但对我和其他人来说有更多的例子会有所帮助。 loeb或其他仿函数是否有Maybe申请?

3 个答案:

答案 0 :(得分:18)

loeb的主要来源(我认为)是Dan Piponi's blog, A Neighborhood of Infinity。他在那里更详细地解释了整个概念。我将复制一点作为答案,并添加一些例子。

loeb实现了一种奇怪的延迟递归

loeb :: Functor a => a (a x -> x) -> a x
loeb x = fmap (\a -> a (loeb x)) x

我们假设我们有一个a类型,其中Functor aa - 代数(类型为a x -> x的函数)。您可能会认为这是一种从值结构中计算值的方法。例如,这里有一些[] - 代数:

length                ::          [Int] -> Int
(!! 3)                ::          [a]   -> a
const 3               :: Num a => [a]   -> a
\l -> l !! 2 + l !! 3 :: Num a => [a]   -> a

我们可以看到这些a - 代数可以使用Functor中存储的值和Functor本身的结构。

另一种思考d :: a x -> x的方法是x的值,它需要一些上下文 - 整个Functor化值a x - 才能进行计算。也许这种解释更清楚地写成Reader (a x) x,强调这只是x的值,它被推迟,等待生成a x上下文。

type Delay q x = q -> x

使用这些想法,我们可以如下描述loeb。我们获得了一个f - 结构,其中包含Delayf个值,其中FunctorFunctor f, f (Delay q x)

q

当然,如果我们获得force :: Functor f => f (Delay q x) -> q -> f x force f q = fmap ($ q) f ,那么我们可以将其转换为非延迟形式。实际上,只有一个(非作弊)函数可以多态地执行此操作:

loeb

q做的是处理force f q实际为fix的额外棘手案例,这是此函数的结果。如果您熟悉loeb :: Functor a => a (Delay (a x) x) -> a x loeb f = fix (force f) ,这正是我们如何产生这种结果的。

Delay

因此,举个例子,我们只需要构建一个包含> loeb [ length :: [Int] -> Int , const 3 :: [Int] -> Int , const 5 :: [Int] -> Int , (!! 2) :: [Int] -> Int , (\l -> l !! 2 + l !! 3) :: [Int] -> Int ] [5, 3, 5, 5, 10] ed值的结构。一个自然的例子是使用之前的列表示例

const 3

在这里我们可以看到列表中充满了延迟等待评估列表结果的值。这个计算可以完全进行,因为数据依赖中没有循环,所以整个事情可以懒得确定。例如,const 5length都可以立即作为值使用。 (!! 2)要求我们知道列表的长度,但不包含任何值,因此它也会立即在我们的固定长度列表中进行。有趣的是延迟等待来自结果列表内部的其他值的值,但是因为const 5仅取决于结果列表的第三个值,这由(\l -> l !! 2 + l !! 3)确定,因此可以是立即可用,计算向前移动。 loeb也会出现同样的想法。


所以你有它:Functor完成这种奇怪的延迟值递归。不过,我们可以在任何类型的Delay上使用它。我们需要做的就是考虑一些有用的Maybe ed值。


Chris Kuklewicz的评论指出,你可以用Maybe作为你的函子来做很多有趣的事情。这是因为maybe (default :: a) (f :: a -> a) :: Maybe a -> a 以上的所有延迟值都采用

形式
Maybe (Delay (Maybe a) a)

并且Just (maybe default f)的所有有趣值都应该是loeb Nothing = Nothing,因为default。所以在一天结束时,loeb (Just (maybe default f)) == fix f 值永远不会被使用 - 我们总是只有那个

{{1}}

所以我们也可以直接写下来。

答案 1 :(得分:1)

以下是一个实例,用于:Map String Float

http://tryplayg.herokuapp.com/try/spreadsheet.hs/edit

具有循环检测和循环分辨率。

该程序计算速度,时间和空间。每一个都取决于其他两个。每个单元格都有两个值:他当前输入的值和表达式作为其他单元格值/表达式的函数。允许循环。

Cell重新计算代码使用了Dan Piponi在2006年的着名loeb表达式。到目前为止,根据我的知识,这个公式在实际工作电子表格上没有任何具体化。这一个接近它。由于loeb在使用循环表达式时进入无限循环,程序会对循环进行计数,并通过逐步用单元格值替换公式来降低复杂性,直到表达式没有循环

此程序配置为在单元格更改时立即重新计算,但可以通过按钮触发它来调整以允许在重新计算之前修改多个单元格。

这是博客pos:

http://haskell-web.blogspot.com.es/2014/09/spreadsheet-like-program-in-browser.html

答案 2 :(得分:1)

您可以将它用于动态编程。我想到的例子是Smith-Waterman algorithm

import Data.Array
import Data.List
import Control.Monad

data Base = T | C | A | G deriving (Eq,Show)
data Diff = Sub Base Base | Id Base | Del Base | Ins Base deriving (Eq,Show)

loeb x = let go = fmap ($ go) x in go

s a b = if a == b then 1 else 0

smithWaterman a' b' = let
  [al,bl] = map length [a',b']
  [a,b] = zipWith (\l s -> array (1,s) $ zip [1..] l) [a',b'] [al,bl]
  h = loeb $ array ((0,0),(al,bl)) $
    [((x,0),const 0) | x <- [0 .. al]] ++
    [((0,y),const 0) | y <- [1 .. bl]] ++
    [((x,y),\h' -> maximum [
       0,
       (h' ! (x - 1,y - 1)) + s (a ! x) (b ! y),
       (h' ! (x - 1, y)) + 1,
       (h' ! (x, y - 1)) + 1
      ]
     ) | x <- [1 .. al], y <- [1 .. bl]]
  ml l (0,0) = l
  ml l (x,0) = ml (Del (a ! x): l) (x - 1, 0)
  ml l (0,y) = ml (Ins (b ! y): l) (0, y - 1)
  ml l (x,y) = let
    (p,e) = maximumBy ((`ap` snd) . (. fst) . (const .) . (. (h !)) . compare . (h !) . fst) [
      ((x - 1,y),Del (a ! x)),
      ((y, x - 1),Ins (b ! y)),
      ((y - 1, x - 1),if a ! x == b ! y then Id (a ! x) else Sub (a ! x) (b ! y))
     ]
    in ml (e : l) p
  in ml [] (al,bl)