Haskell中的语句排序?
我正在尝试编译一个非常简单的haskell程序。要么我不知道如何在Haskell中对语句(表达式)进行排序,要么就是没有办法做到这一点 我基本上想要一个函数的形式:Haskell中的语句排序?,haskell,Haskell,我正在尝试编译一个非常简单的haskell程序。要么我不知道如何在Haskell中对语句(表达式)进行排序,要么就是没有办法做到这一点 我基本上想要一个函数的形式: f = <do stuff 1> <do stuff 2> ... 这也不起作用(更简单,没有递归): 上面的代码可以编译,但在运行时,我得到了一个神秘的信息: No instance for (Num (a0 -> t0)) arising from a use of `go'
f = <do stuff 1>
<do stuff 2>
...
这也不起作用(更简单,没有递归):
上面的代码可以编译,但在运行时,我得到了一个神秘的信息:
No instance for (Num (a0 -> t0))
arising from a use of `go'
Possible fix: add an instance declaration for (Num (a0 -> t0))
In the expression: go 2
In an equation for `it': it = go 2
我在缩进方面有问题吗?排序不正确的问题?还是没有排序功能?如果没有排序,你会直接怎么做
<do stuff>
<tail recursion>
运行示例:
erlang> count([a,b,c,d,e],0).
5
第2条符合我前面描述的模式:
<do stuff>
<tail recursion>
我猜这个特定的例子映射到这里描述的Haskell“让……进来”的人。但如果需要10个“做事”,或20个或更多,该怎么办?这个“let…in”保证是尾部递归的(上面的例子保证是在erlang、prolog、scheme等中)
有没有一种方法可以简单地“串在一起”或“排序”一组语句或表达式?在prolog或erlang中,排序由逗号完成(参见上面的示例)。在c/c++中,它由分号完成。我以为Haskell运算符只是空白,但也许它不是用这种语言实现的?基本上,没有办法实现。Haskell是一种纯粹的函数式语言,既没有变化,也没有语句顺序。模拟序列的一种方法是单子。互联网上有很多教程,我个人建议你阅读或的monad章节。另一件事是:顺序操作在Haskell中不是很惯用。你最好从不同的开始 我不确定你的函数做了什么。也许你需要这样的东西:
go :: Int -> Int
go 0 = 0
go i = go (i-1)
如果该函数接受参数,例如“3”,它将计算go 3->go 2->go 1->go 0->0并得到答案“0”
现在,如果你想要一些排序,你可以使用关键字'do',但我相信这是你现在需要的。如果您试图创建某种“变量”,请查看“let”和“in”语句:
someInput = 7
gogogo 0 = 0
gogogo n =
let
gavk = n + 1
kravk = gavk * 2
out = kravk + 1
in
out
main =
do
putStrLn "this is sample do statement"
putStrLn "gogogo:"
putStrLn $ gogogo someInput
UPD。当你说“做事”时,你是什么意思
- 计算一些东西,转换我们已有的数据
- 与用户交互,读/写文件,从网上下载东西
让
…:
quadraticRoots a b c = let discriminant = b * b - 4 * a * c
root = sqrt discriminant
in case compare discriminant 0 of
LT -> []
EQ -> [-b / (2 * a)]
GT -> [(-b + root) / (2 * a), (-b - root) / (2 * a)]
在第二种情况下,使用do
表示法:
main = do args <- getArgs
case map read args of
[a, b, c] -> putStrLn $ case quadraticRoots a b c of
[] -> "no real roots"
[x] -> "single root: " ++ show x
[x1, x2] -> unwords ["two real roots:", show x1,
"and", show x2]
_ -> hPutStrLn stderr "Please provide three coefficients on the command line"
main=do args putStrLn$case quarticroots a b c of
[]->“没有真正的根”
[x] ->“单根:”++显示x
[x1,x2]->UNWORD[“两个实根:”,显示x1,
“和”,显示x2]
_->hPutStrLn stderr“请在命令行上提供三个系数”
在Haskell中,您不会编写“做事情”的函数。您可以编写计算值的函数。在这种情况下,按照您建议的方式构造函数是没有意义的:
f = <do stuff 1>
<do stuff 2>
将其分解为子表达式可能比较方便
f x y = res1 + res2
where res1 = x * 3
res2 = y + 4
但最终,它只是一个单一的表达
用do
符号编写的一元代码可以按顺序显示为“do stuff”:
f = do
thing1
thing2
但这只是一种错觉。它也分解为一个表达式:
f = thing1 >> thing2
此表达式表示f
是一个值,它是thing1
和thing2
的组成部分。现在,IO代码可能会编译成按顺序“做事情”的代码,但这不是Haskell中的意思。在哈斯克尔,人们不仅仅是“做事”。相反,您需要编写。更新:请注意不要在Haskell中编写Scheme程序。累积参数在惯用的Haskell中很少见,它使用惰性而不是尾部递归
例如,Haskell中的count
的定义类似于
count [] = 0
count (x:xs) = 1 + count xs
你可能会反对这个计划看起来更像一个计划
-- | /O(n)/. 'length' returns the length of a finite list as an 'Int'.
-- It is an instance of the more general 'Data.List.genericLength',
-- the result type of which may be any kind of number.
length :: [a] -> Int
length l = len l 0#
where
len :: [a] -> Int# -> Int
len [] a# = I# a#
len (_:xs) a# = len xs (a# +# 1#)
但这是低级的、非惯用的代码。所引用的结构与上面的count
相同,并且与长度
相比具有更广泛的适用性
genericLength :: (Num i) => [b] -> i
genericLength [] = 0
genericLength (_:l) = 1 + genericLength l
Haskell中的“先做这个,然后再做那个”在纯代码中表示为函数组合。例如,要计算最长子列表的长度,我们需要计算子列表的长度,然后计算这些长度上的最大值。在哈斯凯尔,这是表达出来的
Prelude> :t maximum . map length
maximum . map length :: [[a]] -> Int
或
注意:懒惰增加了细微差别,但总的观点是正确的
甚至在IO
中的“命令式”代码中,例如
main :: IO ()
main = do
putStr "Hello "
purStrLn "world!"
函数组合是隐藏的,因为它与
main :: IO ()
main = putStr "Hello " >>= \_ -> putStrLn "world!"
也许一个使用列表单子的例子会使这一点更清楚。假设我们想要所有的毕达哥拉斯三元组(a,b,c)
,这样就没有一个组分大于某个最大值n
在列表monad中,>=
为,因此上述内容与
triples_stacked :: Integer -> [(Integer,Integer,Integer)]
triples_stacked n =
concatMap (\a ->
concatMap (\b ->
concatMap (\c ->
concatMap (\_ ->
[(a,b,c)])
(guard $ a*a + b*b == c*c))
[b .. n])
[a .. n])
[1 .. n]
缩进显示出结构,令人愉悦,因为它给人的印象是结合了λ和>>=
的Haskell徽标
另一种表达相同语义的方法是
triples_cm n = concatMap step2 [1 .. n] -- step 1
where step2 a = concatMap step3 [a .. n]
where step3 b = concatMap step4 [b .. n]
where step4 c = concatMap step5 (guard $ a*a + b*b == c*c)
where step5 _ = [(a,b,c)]
Haskell的模式匹配已经在幕后进行了case
匹配。而不是
go 0 = 0
go i = case i of
1 -> 2
_ -> 3
go (i-1)
完成你开始的模式
go 0 = 0
go 1 = go (2 - 1)
go _ = go (3 - 1)
请记住,Haskell中的变量是不可变的:它们没有C或Java中的破坏性更新。你只需要定义一个变量的值,然后你就被它卡住了。您可以将go
定义为
go 0 = 0
go x = let i = case x of 1 -> 2
_ -> 3
in go (i - 1)
或
上面的示例都是typecheck,但有相同的大问题,即go
仅在其参数为零时终止。你没有提供足够的信息帮助我们解决这个问题。告诉我们你想做什么,我们可以针对你的情况提供具体的建议。很好,你是一名
main :: IO ()
main = putStr "Hello " >>= \_ -> putStrLn "world!"
import Control.Monad (guard)
triples :: Integer -> [(Integer,Integer,Integer)]
triples n = do
a <- [1 .. n]
b <- [a .. n]
c <- [b .. n]
guard $ a*a + b*b == c*c
return (a,b,c)
-- indented to show nested scopes
triples_bind :: Integer -> [(Integer,Integer,Integer)]
triples_bind n =
[1 .. n] >>= \a ->
[a .. n] >>= \b ->
[b .. n] >>= \c ->
(guard $ a*a + b*b == c*c) >>= \_ ->
return (a,b,c)
triples_stacked :: Integer -> [(Integer,Integer,Integer)]
triples_stacked n =
concatMap (\a ->
concatMap (\b ->
concatMap (\c ->
concatMap (\_ ->
[(a,b,c)])
(guard $ a*a + b*b == c*c))
[b .. n])
[a .. n])
[1 .. n]
triples_cm n = concatMap step2 [1 .. n] -- step 1
where step2 a = concatMap step3 [a .. n]
where step3 b = concatMap step4 [b .. n]
where step4 c = concatMap step5 (guard $ a*a + b*b == c*c)
where step5 _ = [(a,b,c)]
go 0 = 0
go i = case i of
1 -> 2
_ -> 3
go (i-1)
go 0 = 0
go 1 = go (2 - 1)
go _ = go (3 - 1)
go 0 = 0
go x = let i = case x of 1 -> 2
_ -> 3
in go (i - 1)
go 0 = 0
go x | x == 1 = go (2 - 1)
| otherwise = go (3 - 1)
count ([],x) = x
count (_:b, x) =
let y = x + 1
in count (b, y)
count ([],x) = x
count (_:b, x) = count (b, x + 1)
count ([],x) = x
count (_:b, x) = count (b, y) where y = x + 1