[英]How to properly type optional arguments in haskell
I am trying to write a function that recursively determines the amount of steps needed to resolve the collatz conjecture.我正在尝试编写一个函数,该函数递归地确定解决 collatz 猜想所需的步骤数量。 I want the function input to be just the starting input number for the series, with an additional counter variable to be added in the first iteration.
我希望函数输入只是系列的起始输入编号,并在第一次迭代中添加一个额外的计数器变量。 The JS equivalent would look like:
JS 等效项如下所示:
const collatz = (v, count) => {
if (!count) return collatz(v,0)
if (v === 1) return count
if (v % 2 === 0) return collatz(v/2, count + 1)
return collatz(v*3+1, count + 1)
}
My Haskell code:我的哈斯克尔代码:
module CollatzConjecture (collatz) where
collatz :: Integer -> Maybe Integer -> Maybe Integer
collatz v () = collatz v 0
collatz 1 count = Just count
collatz v count
| even v = collatz (div v 2) next
| otherwise = collatz (v * 3 + 1) next
where next = count + 1
But the compiler complains但是编译器抱怨
• Couldn't match type ‘Maybe Integer’ with ‘Integer’
Expected type: Maybe Integer
Actual type: Maybe (Maybe Integer)
• In the expression: Just count
In an equation for ‘collatz’: collatz 1 count = Just count
|
4 | collatz 1 count = Just count
| ^^^^^^^^^^
What is the error in my thinking?我的想法有什么错误?
Don't pollute your function's public API with an extra parameter used only for an implementation detail.不要使用仅用于实现细节的额外参数污染函数的公共 API。 Instead, have your public 1-argument function delegate to a private 2-argument function.
相反,将您的公共 1 参数函数委托给私有 2 参数函数。 Often an internal function like this is named
go
, if you can't think of a better name.如果你想不出更好的名字,像这样的内部函数通常被命名为
go
。
collatz :: Integer -> Integer
collatz = go 0
where go count 1 = count
go count v | even v = next $ div v 2
| otherwise = next $ v * 3 + 1
where next = go $ count + 1
I've also made some other improvements:我还做了一些其他改进:
Maybe Integer
when you never return Nothing
.Nothing
时,没有理由返回一个Maybe Integer
。count
first) to make partial application of go
and next
more convenient.count
),使部分应用go
和next
更方便。next
as an integer, I've defined it as a partial application of go
, so that your two cases only have to repeat next
, rather than go (...) next
.next
定义为整数,而是将其定义为go
的部分应用,因此您的两种情况只需重复next
,而不是go (...) next
。 The function as a whole would also be much simpler if you didn't do the counting yourself at all.如果您根本不自己进行计数,整个函数也会简单得多。 I don't suggest this immediately, since it's fairly unrecognizable compared to your initial attempt, but an experienced Haskeller would write this more like:
我不会立即建议这样做,因为与您最初的尝试相比,它相当难以辨认,但有经验的 Haskeller 会更像这样写:
collatz :: Integer -> Int
collatz = length . takeWhile (/= 1) . iterate step
where step n | even n = n `div` 2
| otherwise = 3 * n + 1
The error in your thinking is that Maybe
is not a keyword, nor is it some kind of a hint to a compiler.您认为的错误在于,
Maybe
不是关键字,也不是对编译器的某种暗示。 It is a type constructor.它是一个类型构造函数。
Maybe Integer
is a concrete, specific data type. Maybe Integer
是一种具体的、特定的数据类型。 It is used to represent the general concept of optionality, but by concrete values (of this type).它用于表示可选性的一般概念,但由具体值(这种类型)表示。
Each value in Haskell has one type. Haskell 中的每个值都有一种类型。 It can't be either
Int
or ()
.它不能是
Int
或()
。 Haskell's sum types are tagged unions . Haskell 的 sum 类型被标记为unions 。
A type is a type -- one type.类型是一种类型——一种类型。 Values of type
Maybe Int
are written either Just i
(where i :: Int
, ie i
has type Int
) or Nothing
, according to the data type definition for Maybe
,根据
Nothing
的数据类型定义, Maybe
Maybe Int
类型的值可以写为Just i
(其中i :: Int
,即i
类型为Int
)或Nothing
,
data Maybe a = Nothing
| Just a
Conceptually, Maybe Int
is the same as Either () Int
-- it does represent maybe an Int
or nothing , ()
:从概念上讲,
Maybe Int
与Either () Int
相同——它确实表示可能是Int
或没有, ()
:
data Either a b = Left a
| Right b
so Just i
is just like Right i
, and Nothing
is like Left ()
.所以
Just i
就像Right i
, Nothing
就像Left ()
。
But not i
or ()
on their own -- they must be tagged with the appropriate data constructor, here Right
or Left
.但不是
i
或()
本身——它们必须用适当的数据构造函数标记,这里是Right
或Left
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.