List 为什么不';我的if语句不起作用吗?
我对Clojure非常陌生,对函数式编程也非常陌生。我期望它返回真或假,但它只是无限递归,似乎根本没有达到真 我的测试数据集如下:List 为什么不';我的if语句不起作用吗?,list,if-statement,clojure,List,If Statement,Clojure,我对Clojure非常陌生,对函数式编程也非常陌生。我期望它返回真或假,但它只是无限递归,似乎根本没有达到真 我的测试数据集如下: (def y (list 1 2 3 4)) ; and I'm passing in 2 for X. (defn occursIn [x y] (if (= y nil) "False" (if (= x first y ) "True" (occursIn x (
(def y (list 1 2 3 4)) ; and I'm passing in 2 for X.
(defn occursIn [x y]
(if (= y nil)
"False"
(if (= x first y )
"True"
(occursIn x (rest y))
)
)
)
尝试此方法,并请注意建议的代码格式-不要单独在一行中留下单独的括号,它们与其他编程语言中的
{}
不同:
(defn occursIn [x y]
(if (empty? y)
"False"
(if (= x (first y))
"True"
(occursIn x (rest y)))))
您忘记在y
列表中首先调用,如下所示:
(first y)
另外,请注意,基本情况并不像您预期的那样工作。改为使用此测试:
(empty? y)
为了完整起见,这里有一种更惯用的方法来编写相同的过程-但是要注意@omiel在注释中指出的边缘情况,如果x
为false
或nil
,这将不起作用:
(defn occursIn [x y]
(if (some #(= x %) y)
"True"
"False"))
(defn occursIn [x y]
(if (empty? y)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn nil ())
; false
一个更好的解决方案,没有边缘案例-正如@mange在评论中所建议的:
(defn occursIn [x y]
(if (every? #(not= x %) y)
"False"
"True"))
尝试此方法,并请注意建议的代码格式-不要单独在一行中留下单独的括号,它们与其他编程语言中的{}
不同:
(defn occursIn [x y]
(if (empty? y)
"False"
(if (= x (first y))
"True"
(occursIn x (rest y)))))
您忘记在y
列表中首先调用,如下所示:
(first y)
另外,请注意,基本情况并不像您预期的那样工作。改为使用此测试:
(empty? y)
为了完整起见,这里有一种更惯用的方法来编写相同的过程-但是要注意@omiel在注释中指出的边缘情况,如果x
为false
或nil
,这将不起作用:
(defn occursIn [x y]
(if (some #(= x %) y)
"True"
"False"))
(defn occursIn [x y]
(if (empty? y)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn nil ())
; false
一个更好的解决方案,没有边缘案例-正如@mange在评论中所建议的:
(defn occursIn [x y]
(if (every? #(not= x %) y)
"False"
"True"))
Oscar的答案是正确且有用的,但我只是想提供一个替代答案,演示如何使函数更接近原始函数,同时仍然是相对惯用的clojure:
(defn occurs-in [needle haystack]
(if-let [[head & tail] (seq haystack)]
(if (= needle head)
"True"
(recur needle tail))
"False"))
在这种情况下,我:
- 使用解构来提取序列上的
头部
/尾部
,而不是使用第一个
/剩余
- 仅当
haystack
为非空时(即如果(seq haystack)
为truthy),才使用if let
绑定这些名称
- 使用
recur
而不是在
中出现,以确保此函数将被编译为使用尾部调用消除,因此它将在不使用额外堆栈帧的情况下再次调用自身
对于小输入来说,这可能不是一个问题,但对于像(发生在1000000(范围))
在惯用命名方面,我使用了出现在
而不是出现在
:通常lisp使用连字符(lisp case
)而不是驼色case(camelCase
)作为名称。Oscar的回答是正确和有用的,但我只是想提供一个替代答案,演示如何制作一个更接近原始函数的函数,同时仍然是相对惯用的clojure:
(defn occurs-in [needle haystack]
(if-let [[head & tail] (seq haystack)]
(if (= needle head)
"True"
(recur needle tail))
"False"))
在这种情况下,我:
- 使用解构来提取序列上的
头部
/尾部
,而不是使用第一个
/剩余
- 仅当
haystack
为非空时(即如果(seq haystack)
为truthy),才使用if let
绑定这些名称
- 使用
recur
而不是在
中出现,以确保此函数将被编译为使用尾部调用消除,因此它将在不使用额外堆栈帧的情况下再次调用自身
对于小输入来说,这可能不是一个问题,但对于像(发生在1000000(范围))
在惯用命名方面,请看我使用了出现在中而不是出现在中:通常lisp使用连字符(lisp case
)而不是驼峰大小写(camelCase
)作为名称。在我们做任何其他事情之前,让我们用布尔True
替换“True”
带有布尔值false
。这样做的原因将变得显而易见
基本问题是rest
从不返回nil
。它返回空列表()
。而(rest())
是()
。因此,您会得到一个无休止的递归调用序列,最终会将堆栈的顶部炸掉
next
确实返回nil
其中rest
返回()
。因此,使用next
而不是rest
,至少我们会得到一个答案:
(def aList (list 1 2 3 4))
(defn occursIn [x y]
(if (= y nil)
false
(if (= x first y)
true
(occursIn x (next y))
)
)
)
(occursIn 2 aList)
; false
。。。但答案是错误的。为什么?正如@OscarLopez所说,在参数y
上调用first
时,在first y
周围缺少括号。就目前而言
(= x first y)
测试x
、first
和y
是否都相等。只有一种方法可以做到这一点:
(occursIn first first)
; true
。。。不是我们想要的。因此,让我们先调用而不是比较它:
(defn occursIn [x y]
(if (= y nil)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn 2 aList)
; true
它起作用了
实际上,基本情况确实有效:
(occursIn 2 ())
; false
。。。但这仅仅是因为下一个
调用将()
变为nil
:恶心
并且它会失火搜索nil
:
(occursIn nil ())
; true
。。。因为(first())
返回nil
并且nil
在被要求成为序列时假装是()
(这称为nil双关语),所以(first nil)
是nil
因此,在Oscar之后,我们最好再次测试y
是否为空,而不是nil
:
(defn occursIn [x y]
(if (some #(= x %) y)
"True"
"False"))
(defn occursIn [x y]
(if (empty? y)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn nil ())
; false
逻辑现在是正确的。让我们使用和和或而不是if
s,并使用显式true
和false
结果(在我看来,这是一种代码味道)来更清楚地说明这一点:
代码现在很容易读取。为此,我们使用了正确的布尔值
只有两个变化: