假设我有以下python代码:
def outer():
string = ""
def inner():
string = "String was changed by a nested function!"
inner()
return string
Run Code Online (Sandbox Code Playgroud)
我想调用outer()来返回"String被嵌套函数改变了!",但我得到了"".我得出结论,Python认为该行string = "string was changed by a nested function!"是对inner()本地新变量的声明.我的问题是:如何告诉Python它应该使用outer()字符串?我不能使用global关键字,因为字符串不是全局的,它只是在外部范围内.想法?
我想创建一个新类,它充当对象的特殊容器类型,并且可以使用方括号访问.
例如,假设我有一个名为的类ListWrapper.假设obj是一个ListWrapper.当我说obj[0],我希望obj.access()用0作为参数调用该方法.然后,我可以回报我想要的任何东西.这可能吗?
好吧,所以我不是Haskell程序员,但我对Haskell背后的许多想法非常感兴趣,并且我正在研究它.但是我被困在第一个方面:我似乎无法绕过Monads,这似乎是相当基础的.我知道有一百万个关于SO的问题要求解释Monads,所以我会更加具体地说明了什么在困扰我:
我读了这篇优秀的文章(Javascript中的介绍),并认为我完全了解Monads.然后我读了Monads上的维基百科条目,看到了:
多态类型(M t)→(t→M u)→(M u)的绑定操作,其中Haskell由中缀运算符表示>> =.它的第一个参数是monadic类型的值,它的第二个参数是一个函数,它从第一个参数的基础类型映射到另一个monadic类型,其结果是在其他monadic类型中.
好的,在我引用的文章中,bind是一个仅占用一个参数的函数.维基百科说两个.我认为我对Monads的理解如下:
但是肯定有一些错误,因为我的bind概念需要一个参数:一个函数.但是(根据维基百科)Haskell的绑定实际上有两个参数!我的错误在哪里?
可能重复:
为什么haskell中不允许这样的函数定义?
我是Haskell世界的新手,从Lisp迁移过来.我正在努力适应Haskell根本不同的世界观,而我发现的许多令人兴奋的事情之一就是类型系统.作为一个Lisper,我想我会尝试在Haskell中实现一个在Lisp世界中非常重要的函数:apply.对于那些不知道的人,apply接受一个函数和一个参数列表,并在这些参数上调用该函数.在Scheme中,(apply + '(1 2 3))与调用相同(+ 1 2 3),并返回6.
我的Haskell代码看起来像这样:
apply x [] = x
apply f (x:xs) = apply (f x) xs
Run Code Online (Sandbox Code Playgroud)
但哈斯克尔抱怨道:
ERROR line 2 - Type error in function binding
*** Term : apply
*** Type : (b -> a) -> [b] -> a
*** Does not match : a -> [b] -> a
*** Because : unification would give infinite type
Run Code Online (Sandbox Code Playgroud)
而且我认为我理解为什么.Apply的类型需要根据列表的长度而有所不同.给出一个例如3个项目的列表,apply的类型需要是:(a -> a -> a -> b) …
我正在尝试为自己的教育编写一个C语法分析器.我知道我可以使用像YACC这样的工具来简化流程,但我想从经验中尽可能多地学习,所以我从头开始.
我的问题是我应该如何处理这样的一行:
doSomethingWith((foo)(bar));
Run Code Online (Sandbox Code Playgroud)
它可能(foo)(bar)是一个类型转换,如:
typedef int foo;
void doSomethingWith(foo aFoo) { ... }
int main() {
float bar = 23.6;
doSomethingWith((foo)(bar));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
或者,它可能(foo)(bar)是一个函数调用,如:
int foo(int bar) { return bar; }
void doSomethingWith(int anInt) { ... }
int main() {
int bar = 10;
doSomethingWith((foo)(bar));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,解析器无法单独通过查看行来确定它处理的两种情况中的哪一种.doSomethingWith((foo)(bar));这让我很烦恼,因为我希望能够将解析阶段与您实际确定的"解释"阶段分开该行typedef int foo;表示foo现在是有效类型.在我想象的场景中,Type a = b + c * d即使Type,a,b,c和d没有在任何地方定义,也会解析得很好,并且只有在实际尝试"解析"标识符时才会出现问题.
所以,我的问题是:"真正的"C解析器如何处理这个?两个阶段之间的分离是我希望只是一个天真的愿望,还是我错过了什么?
我知道quicksort的O(n log n)平均时间复杂度.伪快速排序(当你从足够远的地方看它,具有适当高的抽象级别时只是一个快速排序),通常用于演示函数语言的简洁性如下(在Haskell中给出):
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = quicksort [y | y<-xs, y<p] ++ [p] ++ quicksort [y | y<-xs, y>=p]
Run Code Online (Sandbox Code Playgroud)
好的,所以我知道这件事有问题.最大的问题是它没有排序,这通常是quicksort的一大优势.即使这没关系,它仍然需要比典型的快速排序更长的时间,因为它在分区时必须进行两次列表传递,然后它会进行昂贵的附加操作以将其拼接回来.此外,选择第一个元素作为枢轴不是最佳选择.
但即便考虑所有这些,这个快速排序的平均时间复杂度与标准快速排序不同吗?即,O(n log n)?因为追加和分区仍然具有线性时间复杂度,即使它们效率低下.
Typed Racket做什么类型的推断?我在Racket邮件列表上找到了以下代码段:
Typed Racket类型系统包含许多超出Hindley/Milner风格类型系统支持的功能,因此我们无法使用该推理系统.目前,Typed Racket使用本地类型推断来推断程序中的许多类型,但我们想要推断更多类型 - 这是一个持续的研究领域.
上面的模糊使用术语"本地类型推断",我也听过"发生打字"使用了很多,但我不完全确定这些术语的含义.
在我看来,Typed Racket目前使用的类型推断系统是不必要的弱.这是我的意思的一个例子.以下不进行类型检查:
(struct: pt ([x : Real] [y : Real]))
(define (midpoint p1 p2)
(pt (/ (+ (pt-x p1) (pt-x p2)) 2)
(/ (+ (pt-y p1) (pt-y p2)) 2)))
Run Code Online (Sandbox Code Playgroud)
你必须明确地标注midpoint有(: midpoint (pt pt -> pt)),否则你得到的错误:Type Checker: Expected pt, but got Any in: p1.为什么不能类型检查只是由此得出结论,该类型的p1和p2 必须是pt?这是对Racket实现类型的方式的一个基本限制(也就是说,由于某些Racket更高级的类型特性,这种推理方式实际上有时是错误的),或者这是否有可能在未来实现?
可以(或应该)宏观扩张有副作用吗?例如,这是一个实际上在编译时抓取网页内容的宏:
#lang racket
(require (for-syntax net/url))
(require (for-syntax racket/port))
(define-syntax foo
(lambda (syntx)
(datum->syntax #'lex
(port->string
(get-pure-port
(string->url
(car (cdr (syntax->datum syntx)))))))))
Run Code Online (Sandbox Code Playgroud)
然后,我可以做(foo "http://www.pointlesssites.com/"),它将被取代"\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\r\n\t <and so on>"
这是好习惯吗?我是不是觉得Racket只运行一次这段代码?如果我(display "running...")在宏中添加一行,它只打印一次,但我不想从一个例子中推广......
PS - 我问的原因是因为我实际上认为这有时候非常有用.例如,这是一个库,允许您从Google API Discovery服务加载(在编译时)发现文档,并自动为其创建包装器.我认为,如果库实际上是从Web获取发现文档而不是本地文件,那将会非常酷.
另外,举一个具有不同副作用的宏的例子:我曾经构建了一个宏,它将一小部分Racket翻译成(eta-expanded)lambda演算(当然,它仍然可以在Racket中运行).每当宏完成翻译函数时,它都会将结果存储在字典中,以便稍后调用宏可以在自己的翻译中使用该函数定义.
假设我想在除s-expression中第一项之外的其他内容上触发Scheme宏.例如,假设我想define用中缀样式替换:=,以便:
(a := 5) -> (define a 5)
((square x) := (* x x)) -> (define (square x) (* x x))
Run Code Online (Sandbox Code Playgroud)
实际的转变似乎非常简单.诀窍是让Scheme找到:=表达式并对它们进行宏扩展.我已经考虑过围绕使用带有标准宏的中缀语法的大部分代码,可能是:(with-infix-define expr1 expr2 ...)和标准宏遍历其主体中的表达式并执行任何必要的转换.我知道如果我采用这种方法,我必须小心避免转换实际上应该是数据的列表,例如引用列表和quasiquoted列表的某些部分.我想象的一个例子:
(with-infix-define
((make-adder n) := (lambda (m) (+ n m)))
((foo) :=
(add-3 := (make-adder 3))
(add-6 := (make-adder 6))
(let ((a 5) (b 6))
(+ (add-3 a) (add-6 b))))
(display (foo))
(display '(This := should not be transformed))
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是双重的:
with-infix-define条路线,我是否必须注意除引号和准引号之外的任何绊脚石?我第一次看Clojure core.async,正在经历Rich Hickey的精彩演讲:http://www.infoq.com/presentations/clojure-core-async
我对他在演讲结束时展示的例子有疑问:

根据Rich的说法,这个例子基本上试图获得特定查询的Web,视频和图像结果.它为每个结果并行尝试两个不同的源,并为每个结果提取最快的结果.并且整个操作可能不会超过80毫秒,所以如果我们不能在80毫秒内获得例如图像结果,我们就会放弃."最快"的功能会创建并返回一个新频道,并启动两个过程来竞赛以检索结果并将其放在频道上.然后我们将第一个结果从"最快"的通道中取出并将其打到c通道上.
我的问题:在我们取得第一个结果之后,这三个临时的,未命名的"最快"频道会发生什么?据推测,仍有一个停止过程试图将第二个结果放到通道上,但是没有人在听,所以它从未实际完成.由于频道从未与任何东西绑定,因此我们似乎无法再对它做任何事情.流程和渠道是否会"意识到"没有人关心他们的结果并自我清理?或者我们基本上只是"泄漏"此代码中的三个通道/进程?
haskell ×3
lisp ×2
macros ×2
python ×2
racket ×2
types ×2
c ×1
casting ×1
clojure ×1
composition ×1
core.async ×1
currying ×1
monads ×1
parsing ×1
polyvariadic ×1
quicksort ×1
scheme ×1
scope ×1
side-effects ×1
typed-racket ×1