在Go语言中的Scheme解释器

huangapple go评论122阅读模式
英文:

Scheme interpreter in Go

问题

我是你的中文翻译助手,以下是翻译好的内容:

我是一个相当基础的Go程序员,最近在研究一个小的Scheme解释器,试图理解它的工作原理。

我在这里找到了它:
https://pkelchte.wordpress.com/2013/12/31/scm-go/

我阅读了网页,但仍然难以理解它的工作原理,因为源代码显然是由一个比我更熟悉Go的人编写的。

特别是有这些行让我难以理解:

  1. e := expression.(type) // 第73行

我不确定.(type)部分是什么意思,我以为它是类型转换,但它看起来不像我之前见过的类型转换。

  1. switch p := procedure.(type) {
  2. case func(...scmer) scmer:
  3. value = p(args...)
  4. case proc:
  5. en := &env{make(vars), p.en}
  6. switch params := p.params.(type) {
  7. case []scmer:
  8. for i, param := range params {
  9. en.vars[param.(symbol)] = args[i]
  10. }
  11. default:
  12. en.vars[params.(symbol)] = args
  13. }
  14. value = eval(p.body, en)

我实际上不太理解这段代码。第73至86行。

  1. *tokens = (*tokens)[1:] // 第208行

由于它的奇怪语法,我不确定这行代码的意思。我知道它涉及指针,并且括号是因为*。但我不确定这行代码在做什么。

最后是这些行:

  1. token := (*tokens)[0]
  2. *tokens = (*tokens)[1:]
  3. switch token {
  4. case "(": //列表开始
  5. L := make([]scmer, 0)
  6. for (*tokens)[0] != ")" {
  7. if i := readFrom(tokens); i != symbol("") {
  8. L = append(L, i)
  9. }
  10. }
  11. *tokens = (*tokens)[1:]
  12. return L

我也不知道这些行的作用。第198至209行。

如果你需要完整的代码,这是它的完整代码。我知道它有250行,但我希望能尽可能多地解释它的功能。

  1. /*
  2. * A minimal Scheme interpreter, as seen in lis.py and SICP
  3. * http://norvig.com/lispy.html
  4. * http://mitpress.mit.edu/sicp/full-text/sicp/book/node77.html
  5. *
  6. * Pieter Kelchtermans 2013
  7. * LICENSE: WTFPL 2.0
  8. */
  9. package main
  10. import (
  11. "bufio"
  12. "fmt"
  13. "log"
  14. "os"
  15. "reflect"
  16. "strconv"
  17. "strings"
  18. )
  19. func main() {
  20. Repl()
  21. }
  22. /*
  23. Eval / Apply
  24. */
  25. func eval(expression scmer, en *env) (value scmer) {
  26. switch e := expression.(type) {
  27. case number:
  28. value = e
  29. case symbol:
  30. value = en.Find(e).vars[e]
  31. case []scmer:
  32. switch car, _ := e[0].(symbol); car {
  33. case "quote":
  34. value = e[1]
  35. case "if":
  36. if eval(e[1], en).(bool) {
  37. value = eval(e[2], en)
  38. } else {
  39. value = eval(e[3], en)
  40. }
  41. case "set!":
  42. v := e[1].(symbol)
  43. en.Find(v).vars[v] = eval(e[2], en)
  44. value = "ok"
  45. case "define":
  46. en.vars[e[1].(symbol)] = eval(e[2], en)
  47. value = "ok"
  48. case "lambda":
  49. value = proc{e[1], e[2], en}
  50. case "begin":
  51. for _, i := range e[1:] {
  52. value = eval(i, en)
  53. }
  54. default:
  55. operands := e[1:]
  56. values := make([]scmer, len(operands))
  57. for i, x := range operands {
  58. values[i] = eval(x, en)
  59. }
  60. value = apply(eval(e[0], en), values)
  61. }
  62. default:
  63. log.Println("Unknown expression type - EVAL", e)
  64. }
  65. return
  66. }
  67. func apply(procedure scmer, args []scmer) (value scmer) {
  68. switch p := procedure.(type) {
  69. case func(...scmer) scmer:
  70. value = p(args...)
  71. case proc:
  72. en := &env{make(vars), p.en}
  73. switch params := p.params.(type) {
  74. case []scmer:
  75. for i, param := range params {
  76. en.vars[param.(symbol)] = args[i]
  77. }
  78. default:
  79. en.vars[params.(symbol)] = args
  80. }
  81. value = eval(p.body, en)
  82. default:
  83. log.Println("Unknown procedure type - APPLY", p)
  84. }
  85. return
  86. }
  87. type proc struct {
  88. params, body scmer
  89. en *env
  90. }
  91. /*
  92. Environments
  93. */
  94. type vars map[symbol]scmer
  95. type env struct {
  96. vars
  97. outer *env
  98. }
  99. func (e *env) Find(s symbol) *env {
  100. if _, ok := e.vars
    展开收缩
    ; ok {
  101. return e
  102. } else {
  103. return e.outer.Find(s)
  104. }
  105. }
  106. /*
  107. Primitives
  108. */
  109. var globalenv env
  110. func init() {
  111. globalenv = env{
  112. vars{ //aka an incomplete set of compiled-in functions
  113. "+": func(a ...scmer) scmer {
  114. v := a[0].(number)
  115. for _, i := range a[1:] {
  116. v += i.(number)
  117. }
  118. return v
  119. },
  120. "-": func(a ...scmer) scmer {
  121. v := a[0].(number)
  122. for _, i := range a[1:] {
  123. v -= i.(number)
  124. }
  125. return v
  126. },
  127. "*": func(a ...scmer) scmer {
  128. v := a[0].(number)
  129. for _, i := range a[1:] {
  130. v *= i.(number)
  131. }
  132. return v
  133. },
  134. "/": func(a ...scmer) scmer {
  135. v := a[0].(number)
  136. for _, i := range a[1:] {
  137. v /= i.(number)
  138. }
  139. return v
  140. },
  141. "<=": func(a ...scmer) scmer {
  142. return a[0].(number) <= a[1].(number)
  143. },
  144. "equal?": func(a ...scmer) scmer {
  145. return reflect.DeepEqual(a[0], a[1])
  146. },
  147. "cons": func(a ...scmer) scmer {
  148. switch car := a[0]; cdr := a[1].(type) {
  149. case []scmer:
  150. return append([]scmer{car}, cdr...)
  151. default:
  152. return []scmer{car, cdr}
  153. }
  154. },
  155. "car": func(a ...scmer) scmer {
  156. return a[0].([]scmer)[0]
  157. },
  158. "cdr": func(a ...scmer) scmer {
  159. return a[0].([]scmer)[1:]
  160. },
  161. "list": eval(read(
  162. "(lambda z z)"),
  163. &globalenv),
  164. },
  165. nil}
  166. }
  167. /*
  168. Parsing
  169. */
  170. //symbols, numbers, expressions, procedures, lists, ... all implement this interface, which enables passing them along in the interpreter
  171. type scmer interface{}
  172. type symbol string //symbols are represented by strings
  173. type number float64 //numbers by float64
  174. func read(s string) (expression scmer) {
  175. tokens := tokenize(s)
  176. return readFrom(&tokens)
  177. }
  178. //Syntactic Analysis
  179. func readFrom(tokens *[]string) (expression scmer) {
  180. //pop first element from tokens
  181. token := (*tokens)[0]
  182. *tokens = (*tokens)[1:]
  183. switch token {
  184. case "(": //a list begins
  185. L := make([]scmer, 0)
  186. for (*tokens)[0] != ")" {
  187. if i := readFrom(tokens); i != symbol("") {
  188. L = append(L, i)
  189. }
  190. }
  191. *tokens = (*tokens)[1:]
  192. return L
  193. default: //an atom occurs
  194. if f, err := strconv.ParseFloat(token, 64); err == nil {
  195. return number(f)
  196. } else {
  197. return symbol(token)
  198. }
  199. }
  200. }
  201. //Lexical Analysis
  202. func tokenize(s string) []string {
  203. return strings.Split(
  204. strings.Replace(strings.Replace(s, "(", "( ",
  205. -1), ")", " )",
  206. -1), " ")
  207. }
  208. /*
  209. Interactivity
  210. */
  211. func String(v scmer) string {
  212. switch v := v.(type) {
  213. case []scmer:
  214. l := make([]string, len(v))
  215. for i, x := range v {
  216. l[i] = String(x)
  217. }
  218. return "(" + strings.Join(l, " ") + ")"
  219. default:
  220. return fmt.Sprint(v)
  221. }
  222. }
  223. func Repl() {
  224. scanner := bufio.NewScanner(os.Stdin)
  225. for fmt.Print("> "); scanner.Scan(); fmt.Print("> ") {
  226. fmt.Println("==>", String(eval(read(scanner.Text()), &globalenv)))
  227. }
  228. }

希望对你有帮助!如果有任何其他问题,请随时提问。

英文:

I'm quite a basic Go programmer and I've been taking a look at this small Scheme interpreter and I've been trying to understand how it works.

I found it here:
https://pkelchte.wordpress.com/2013/12/31/scm-go/

I read the webpage, but I'm still struggling to understand how it works because the source code is obviously written by someone who's a lot more familiar with Go than I am.

Particularly there's these lines that I'm struggling to understand:

  1. e := expression.(type) // Line 73

I'm not sure what the .(type) part means, I thought it was casting but it doesn't look like the casting I've seen before.

  1. switch p := procedure.(type) {
  2. case func(...scmer) scmer:
  3. value = p(args...)
  4. case proc:
  5. en := &amp;env{make(vars), p.en}
  6. switch params := p.params.(type) {
  7. case []scmer:
  8. for i, param := range params {
  9. en.vars[param.(symbol)] = args[i]
  10. }
  11. default:
  12. en.vars[params.(symbol)] = args
  13. }
  14. value = eval(p.body, en)

I don't really understand any of this code to be honest. Lines 73 - 86

  1. *tokens = (*tokens)[1:] // Line 208

I'm not sure what this line means due to it's weird syntax. I get that its pointers and that the parenthesises are because of the *. But I'm not sure what that lines doing.

Finally there's these lines:

  1. token := (*tokens)[0]
  2. *tokens = (*tokens)[1:]
  3. switch token {
  4. case &quot;(&quot;: //a list begins
  5. L := make([]scmer, 0)
  6. for (*tokens)[0] != &quot;)&quot; {
  7. if i := readFrom(tokens); i != symbol(&quot;&quot;) {
  8. L = append(L, i)
  9. }
  10. }
  11. *tokens = (*tokens)[1:]
  12. return L

I don't know what these lines do either. Lines 198 - 209

Here's the complete code if you want it, I realise it's 250 lines long but I'd really appreciate as many explanations about what its doing as possible.

  1. /*
  2. * A minimal Scheme interpreter, as seen in lis.py and SICP
  3. * http://norvig.com/lispy.html
  4. * http://mitpress.mit.edu/sicp/full-text/sicp/book/node77.html
  5. *
  6. * Pieter Kelchtermans 2013
  7. * LICENSE: WTFPL 2.0
  8. */
  9. package main
  10. import (
  11. &quot;bufio&quot;
  12. &quot;fmt&quot;
  13. &quot;log&quot;
  14. &quot;os&quot;
  15. &quot;reflect&quot;
  16. &quot;strconv&quot;
  17. &quot;strings&quot;
  18. )
  19. func main() {
  20. Repl()
  21. }
  22. /*
  23. Eval / Apply
  24. */
  25. func eval(expression scmer, en *env) (value scmer) {
  26. switch e := expression.(type) {
  27. case number:
  28. value = e
  29. case symbol:
  30. value = en.Find(e).vars[e]
  31. case []scmer:
  32. switch car, _ := e[0].(symbol); car {
  33. case &quot;quote&quot;:
  34. value = e[1]
  35. case &quot;if&quot;:
  36. if eval(e[1], en).(bool) {
  37. value = eval(e[2], en)
  38. } else {
  39. value = eval(e[3], en)
  40. }
  41. case &quot;set!&quot;:
  42. v := e[1].(symbol)
  43. en.Find(v).vars[v] = eval(e[2], en)
  44. value = &quot;ok&quot;
  45. case &quot;define&quot;:
  46. en.vars[e[1].(symbol)] = eval(e[2], en)
  47. value = &quot;ok&quot;
  48. case &quot;lambda&quot;:
  49. value = proc{e[1], e[2], en}
  50. case &quot;begin&quot;:
  51. for _, i := range e[1:] {
  52. value = eval(i, en)
  53. }
  54. default:
  55. operands := e[1:]
  56. values := make([]scmer, len(operands))
  57. for i, x := range operands {
  58. values[i] = eval(x, en)
  59. }
  60. value = apply(eval(e[0], en), values)
  61. }
  62. default:
  63. log.Println(&quot;Unknown expression type - EVAL&quot;, e)
  64. }
  65. return
  66. }
  67. func apply(procedure scmer, args []scmer) (value scmer) {
  68. switch p := procedure.(type) {
  69. case func(...scmer) scmer:
  70. value = p(args...)
  71. case proc:
  72. en := &amp;env{make(vars), p.en}
  73. switch params := p.params.(type) {
  74. case []scmer:
  75. for i, param := range params {
  76. en.vars[param.(symbol)] = args[i]
  77. }
  78. default:
  79. en.vars[params.(symbol)] = args
  80. }
  81. value = eval(p.body, en)
  82. default:
  83. log.Println(&quot;Unknown procedure type - APPLY&quot;, p)
  84. }
  85. return
  86. }
  87. type proc struct {
  88. params, body scmer
  89. en *env
  90. }
  91. /*
  92. Environments
  93. */
  94. type vars map[symbol]scmer
  95. type env struct {
  96. vars
  97. outer *env
  98. }
  99. func (e *env) Find(s symbol) *env {
  100. if _, ok := e.vars
    展开收缩
    ; ok {
  101. return e
  102. } else {
  103. return e.outer.Find(s)
  104. }
  105. }
  106. /*
  107. Primitives
  108. */
  109. var globalenv env
  110. func init() {
  111. globalenv = env{
  112. vars{ //aka an incomplete set of compiled-in functions
  113. &quot;+&quot;: func(a ...scmer) scmer {
  114. v := a[0].(number)
  115. for _, i := range a[1:] {
  116. v += i.(number)
  117. }
  118. return v
  119. },
  120. &quot;-&quot;: func(a ...scmer) scmer {
  121. v := a[0].(number)
  122. for _, i := range a[1:] {
  123. v -= i.(number)
  124. }
  125. return v
  126. },
  127. &quot;*&quot;: func(a ...scmer) scmer {
  128. v := a[0].(number)
  129. for _, i := range a[1:] {
  130. v *= i.(number)
  131. }
  132. return v
  133. },
  134. &quot;/&quot;: func(a ...scmer) scmer {
  135. v := a[0].(number)
  136. for _, i := range a[1:] {
  137. v /= i.(number)
  138. }
  139. return v
  140. },
  141. &quot;&lt;=&quot;: func(a ...scmer) scmer {
  142. return a[0].(number) &lt;= a[1].(number)
  143. },
  144. &quot;equal?&quot;: func(a ...scmer) scmer {
  145. return reflect.DeepEqual(a[0], a[1])
  146. },
  147. &quot;cons&quot;: func(a ...scmer) scmer {
  148. switch car := a[0]; cdr := a[1].(type) {
  149. case []scmer:
  150. return append([]scmer{car}, cdr...)
  151. default:
  152. return []scmer{car, cdr}
  153. }
  154. },
  155. &quot;car&quot;: func(a ...scmer) scmer {
  156. return a[0].([]scmer)[0]
  157. },
  158. &quot;cdr&quot;: func(a ...scmer) scmer {
  159. return a[0].([]scmer)[1:]
  160. },
  161. &quot;list&quot;: eval(read(
  162. &quot;(lambda z z)&quot;),
  163. &amp;globalenv),
  164. },
  165. nil}
  166. }
  167. /*
  168. Parsing
  169. */
  170. //symbols, numbers, expressions, procedures, lists, ... all implement this interface, which enables passing them along in the interpreter
  171. type scmer interface{}
  172. type symbol string //symbols are represented by strings
  173. type number float64 //numbers by float64
  174. func read(s string) (expression scmer) {
  175. tokens := tokenize(s)
  176. return readFrom(&amp;tokens)
  177. }
  178. //Syntactic Analysis
  179. func readFrom(tokens *[]string) (expression scmer) {
  180. //pop first element from tokens
  181. token := (*tokens)[0]
  182. *tokens = (*tokens)[1:]
  183. switch token {
  184. case &quot;(&quot;: //a list begins
  185. L := make([]scmer, 0)
  186. for (*tokens)[0] != &quot;)&quot; {
  187. if i := readFrom(tokens); i != symbol(&quot;&quot;) {
  188. L = append(L, i)
  189. }
  190. }
  191. *tokens = (*tokens)[1:]
  192. return L
  193. default: //an atom occurs
  194. if f, err := strconv.ParseFloat(token, 64); err == nil {
  195. return number(f)
  196. } else {
  197. return symbol(token)
  198. }
  199. }
  200. }
  201. //Lexical Analysis
  202. func tokenize(s string) []string {
  203. return strings.Split(
  204. strings.Replace(strings.Replace(s, &quot;(&quot;, &quot;( &quot;,
  205. -1), &quot;)&quot;, &quot; )&quot;,
  206. -1), &quot; &quot;)
  207. }
  208. /*
  209. Interactivity
  210. */
  211. func String(v scmer) string {
  212. switch v := v.(type) {
  213. case []scmer:
  214. l := make([]string, len(v))
  215. for i, x := range v {
  216. l[i] = String(x)
  217. }
  218. return &quot;(&quot; + strings.Join(l, &quot; &quot;) + &quot;)&quot;
  219. default:
  220. return fmt.Sprint(v)
  221. }
  222. }
  223. func Repl() {
  224. scanner := bufio.NewScanner(os.Stdin)
  225. for fmt.Print(&quot;&gt; &quot;); scanner.Scan(); fmt.Print(&quot;&gt; &quot;) {
  226. fmt.Println(&quot;==&gt;&quot;, String(eval(read(scanner.Text()), &amp;globalenv)))
  227. }
  228. }

答案1

得分: 3

第一个是类型切换。你可以在这里阅读更多关于它的内容:链接

第二个是像Python中的切片操作(如果你了解的话,应该很熟悉):

  1. ls = ls[1:]

我们跳过了第一个元素,取出了切片/列表的剩余部分。

从你的评论中我看出,我认为这不是一个好的起点来尝试使用Go语言。

英文:

First one is type switch. You can read about it more here.

Second one is slicing like in python (if you know it, should be familiar)

  1. ls = ls[1:]

We're skipping first item and taking the rest of the slice/list.

As I see from your comments, I think it's not a good starting point to experiment with golang.

答案2

得分: 2

e := expression.(type) 是一个类型断言

switch p := procedure.(type) {(后面跟着的case语句)是一个类型切换

*tokens = (*tokens)[1:] 是一个切片表达式,用于改变*tokens中存储的值。

  1. token := (*tokens)[0] // 将token设置为tokens切片的第一个元素。
  2. *tokens = (*tokens)[1:] // 更新tokens,移除第一个元素。
  3. switch token { // 根据token进行切换。
  4. case "(": //列表开始 // 如果token是"("
  5. L := make([]scmer, 0) // 创建一个新的空切片。
  6. for (*tokens)[0] != ")" { // 当tokens的第一个元素不是")"时:
  7. // 从tokens中读取;如果不是空符号:
  8. if i := readFrom(tokens); i != symbol("") {
  9. L = append(L, i) // 将读取的标记(存储在i中)添加到L中。
  10. }
  11. }
  12. *tokens = (*tokens)[1:] // 从tokens中移除第一个元素。
  13. return L // 返回新创建的切片。
英文:

e := expression.(type) is a type assertion.

switch p := procedure.(type) { (with the following case statements) is a type switch.

*tokens = (*tokens)[1:] is a slice expression changing the value stored in *tokens.

  1. token := (*tokens)[0] // Set token to first element of tokens slice.
  2. *tokens = (*tokens)[1:] // Update tokens to remove first element.
  3. switch token { // Switch on token.
  4. case &quot;(&quot;: //a list begins // If token is &quot;(&quot;
  5. L := make([]scmer, 0) // Make a new, empty slice.
  6. for (*tokens)[0] != &quot;)&quot; { // While the first element of tokens is not &quot;)&quot;:
  7. // Read from tokens; if not empty symbol:
  8. if i := readFrom(tokens); i != symbol(&quot;&quot;) {
  9. L = append(L, i) // Add the token read (in i) to L.
  10. }
  11. }
  12. *tokens = (*tokens)[1:] // Remove the first element from tokens.
  13. return L // Return the newly created slice.

huangapple
  • 本文由 发表于 2015年7月8日 05:26:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/31279557.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定