【问题标题】:Read the proper input to a variable读取变量的正确输入
【发布时间】:2017-11-15 05:15:11
【问题描述】:

我想要一个包含integer 的变量,它来自用户的输入。它既不能接受字符串,也不能接受十进制数字。

我需要一些帮助来了解我在这里做错了什么。

到目前为止我的代码:

感谢您的帮助。

(format t "~%Enter a number: ")
(loop (defvar numb (read))
(cond (((rationalp numb)1)
        (print "No decimal numbers are allowed, please enter an integer"))
      (((stringp numb)1)
        (print "No strings are allowed, please enter an integer"))
)
(when ((integerp numb)1) (return numb))
)

【问题讨论】:

标签: common-lisp clisp


【解决方案1】:

工作代码

我会这样做:

(defun ask-and-read (prompt)
  "Prompt the user and read his input."
  (princ prompt *query-io*)
  (force-output *query-io*)  ; flush the buffers
  (let ((*read-eval* nil))   ; close the security hole
    (read *query-io*)))

(defun request-object (prompt predicate)
  "Ask the user for an object using prompt.
Only accept data which satisfies the predicate."
  (loop
    for object = (ask-and-read prompt)
    when (funcall predicate object)
    return object
    do (format *query-io* "Alas, ~S (~S) does not satisfy ~S, please try again~%"
               object (type-of object) predicate)))

例子:

> (request-object "Enter an integer: " #'integerp)
Enter an integer: 4.6
Alas, 4.6 (SINGLE-FLOAT) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: 5/7
Alas, 5/7 (RATIO) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: asdf
Alas, ASDF (SYMBOL) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: 7
==> 7
> (request-object "Enter a real: " #'realp)
Enter a real: 4.5
==> 4.5
> (request-object "Enter a real: " #'realp)
Enter a real: 5/8
==> 5/8
> (request-object "Enter a real: " #'realp)
Enter a real: "sdf"
Alas, "sdf" ((SIMPLE-BASE-STRING 3)) does not satisfy #<SYSTEM-FUNCTION REALP>, please try again
Enter a real: 8
==> 8

请参阅我使用的设施的文档:

你的错误

代码格式

您的代码不可读,因为您的缩进不正确。 Lispers 不计算括号 - 这是编译器和编辑器的工作。 我们看缩进。 请帮自己一个忙并使用 Emacs - 它会为您缩进代码,您自己也会经常看到错误。

Defvar 是顶级表单

首先,defvar 是一个顶级表单,用于定义全局变量,而不是设置它们。 后续调用不会改变值:

(defvar *abc* 1)
*abc*
==> 1
(defvar *abc* 10)
*abc*
==> 1   ; not 10!

使用setq 设置变量。

局部变量优于全局变量

虽然 Lisp 确实允许全局变量,但主要的编程 Lisp 中的风格是函数式风格:每个函数都接收它的 “输入”数据作为参数,并将其“输出”数据作为值返回。 要实现函数式风格,最好使用局部变量而不是全局变量。 您可以通过let or let* 或在loop 中创建局部变量,请参阅 Local Variable Initializations.

Cond 和 When 有非常具体的语法

您的condwhen 表单中有额外的括号和1(?!)。

记住,parens are meaningful in Lisp

安全第一!

*read-eval* 绑定到nilread 之前是必要的 如果用户输入#.(launch-nuclear-missiles),则避免发生核战争 响应您的提示,因为通常read 会评估任何内容 在#. 之后。

【讨论】:

  • 非常感谢。很好解释。是的,在这里询问之后我一直在尝试,我认为这个 1 是错误的。我认为以某种方式需要它才能与真实的陈述相匹配。我错了哈哈再次感谢
  • 请注意,在便携式 CL 中打印提示后需要 FINISH-OUTPUT。
  • 人们可能希望使用*query-io* 来获得此类提示。
猜你喜欢
  • 2019-04-24
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 2021-04-09
  • 2020-06-08
  • 2021-09-01
相关资源
最近更新 更多