【发布时间】:2015-03-02 16:15:39
【问题描述】:
序幕:
几年前,我在阅读“LYAH”时曾涉足 Haskell。再加上使用了一点Mathematica,我想说我掌握了(或多或少)一些函数式编程的基本思想,例如不变性、函数组合、currying、maps、folds、惰性求值等。
我认为我从 LYAH 读到的最后一件事是函子(我的记忆模糊不清),这意味着我在“可怕”的单子中停了下来(不是因为对它们的一些非理性的恐惧,而是我无法保持由于多种原因,我当时对 Haskell 的研究有所增加。)我时不时地提到了 monad,但我对它们的看法相当模糊。
现在我在玩 Swift,它对函数式范式有一些支持。 我的主要问题是了解我对下面指定问题的解决方案与 monad 有什么关系(如果有的话)。 如果不出意外,它可能会给我重新学习纯函数式编程的动力哈斯克尔。
所以这是一般形式的问题:我有一堆T -> T 类型的函数,我希望能够以这样的方式“链接”它们,当我应用类型参数时T,我不仅在参数上得到了这些函数组成对应的值,还得到了中间值的序列(每个函数的返回值在前一个函数的返回值所具有的序列中)作为参数应用)在一个数组中。
现在我知道 Swift 对从函数内部修改全局变量(可用于存储状态)毫无疑虑,但我想以一种功能上“更纯粹”的方式来处理它。我的第一个想法是将我的函数修改为具有[T] -> [T] 类型,这样每个函数都会使用一个包含所有先前状态的数组,并返回一个带有最后附加返回值的数组。但显然这不是一个简洁的解决方案,它掩盖了这样一个事实,即我的函数的计算实际上并不依赖于过去的值历史。
所以这是我想出的解决方案:
infix operator << {
associativity right
}
func wrap<T>(f: T -> T) -> (T -> (T, [T])) {
return { x in
(f(x), [x]) }
}
func <<<T>(left: T -> T, right: T -> (T, [T])) -> T -> (T, [T]) {
return { x in
let r = right(x)
let lr0 = left(r.0)
return (lr0, r.1 + [r.0]) }
}
func <<<T>(left: T -> T, right: T -> T) -> T -> (T, [T]) {
return left << wrap(right)
}
// Simple example; Int -> Int functions:
let addOne: Int -> Int = { x in x + 1 }
let mulTwo: Int -> Int = { x in 2 * x }
let subThree: Int -> Int = { x in x - 3 }
let seqOfOps = addOne << mulTwo << addOne << subThree
seqOfOps(10) // (.0 17, [10, 7, 8, 16]) // final value and history respectively
(我没有费心解释它,因为我希望能够解决我的问题的人应该能够跟进。)
那么我的想法是否与 monad 概念有关,如果是,那么如何(以及如何不)?如果不是,我的解决方案将如何修改为“适当的”一元解决方案?
我意识到,通过定义 protocol 并使用类型约束,我应该能够概括“状态”的概念,如果这是考虑的一点的话。
【问题讨论】:
-
我认为这实际上可能与
Writermonad 有关。它的“经典”目的是聚合中间内容(如日志记录)。<<函数在某种程度上看起来像带有纯函数的 Kleisli 组合。 -
“Kleisli 组合” - 很酷的名字。我得查一下。
标签: swift functional-programming monads