(这两天听ZT哥不断的提起这个语言,Haskell。也许是他强大的数学背景吧,所以他对这个语言非常的情有独钟。于是我就找了一个入门教程来看一下,放到这里备忘。)

Haskell教程 
by rufi  2003.3.21 -- 2003.4.2 

一.序 

1.什么是Haskell? 

Haskell是一种函数编程语言. 1980年代以前对函数编程有很多研究, 但不同的研究者使用各自不同的语法记号, 一起交流时造成一些不便. 后来1987年的时候, 在FPCA'87会议上制定了统一的Haskell语言. Haskell吸收了各家的长处, 是一种纯粹的函数编程语言,并根据科学家Haskell B.Curry的名字命名. Haskell经过多年的发展完善, 目前使用的版本是Haskell 98. 

2.Haskell有什么特点? 

相对Haskell来说,传统的Basic,Pascal,C++,C#,Java,Python等都是命令(imperative)编程语言, 程序语句有一定的执行次序. 函数(functional)编程语言则给出执行的内容, 关注于更高层次的"做什么"而不是"怎么做", 这就是二者最明显的一个区别。函数编程语言的语法功能非常强,使编程的效率大幅提高。 
Haskell是世界上公认的语法最优美最简洁的一种语言。的确,Haskell语言是写给人看的,而不是写给机器看的。另一方面,这也使得的Haskell的编译技术成为一个难点。从以人为本的角度来看,程序员的时间比机器的时间更宝贵,所以Haskell是明智的选择。 

3.如何获得Haskell? 

Haskell是一个公共的语言定义, 任何人都可以编写它的实现(implementation), 因而Haskell有很多解释器(比如Hugs)和编译器(比如GHC), 它们都可以在www.haskell.org上得到. 解释器的优点是便于学习和开发,程序写好后不需要编译直接就可以运行,编译器则可以将程序编译可独立执行的文件,便于发布. Haskell既能解释执行, 也能槐槐嘁? 这也是优于其他语言的一个地方. 

附:Hugs使用指南 

本文中的示例程序都将在Hugs中运行, 在这里简要介绍一下Hugs的使用方法。Hugs可以在http://www.haskell.org/hugs/下载,安装文件只有2.8M, 是学Haskell的必备工具. 

使用方法: 

1.用你自己喜欢的文本编辑器将源程序写好, 保存到文件中, 文件以扩展名 hs 结尾. 

2.运行Hugs, 出现提示符: Prelude> ,表示Prelude库已经装载. 

3.输入:? 可以查看可供使用的一些命令的说明 

4. 先输入:!, 然后就可以输入DOS命令并执行. 比如输入:!dir查看当前的工作目录 

5. 输入:cd directory_name 将工作目录改为你保存源文件的目录 

6. 输入:l file_name 将源程序载入, 提示符变为Main> 

现在就可以在提示符后输入各种表达式以检验所定义的函数的功能, 执行所需的运算. 

注意: 在提示符后不可以定义新的函数, 因为Haskell中各语句不是顺序执行的, 而把整个源文件当作一个整体来处理, 在编辑器中修改源程序并保存后, 只要输入:r就重新载入, 改动就生效了. 


二.语法概要 

1.注释有两种: 一种以"--"开始到行尾结束, 一种以"{-"开始,以"-}"结束,可以延续多行. 

2.表达式和函数都有类型,但类型声明不是必需的,有一套类型推断系统可以推断出所涉及的类型. 

3.函数的定义多使用模式(pattern)匹配的方法, 两个标识符(identifier)邻接就表示函数调用. 

4.函数变量和类型变量的标识符以小写字母开头, 类型构造和模块的标识符以大写字母开头. 

5.语句块以缩进区分, 从同一列开始的语句属于同一个块. 

6.保留字: case class data default deriving do else if import in infix infixl infixr instance let module newtype of then type where _ 

7.运算符可以自定义,由以下符号进行组合: 
: # $ % & * + - = . / \ < > ? ! @ ^ | 
预定义的运算符有: 
+  -  *  /  ^  $  ++  .  &&  ||  ==  /= <=  >=  <  > 
: //  =  @  ->  =>  ..  ::  <-  !! 

8.数字: 123  12.3  1.23e5  0o67  0x3A 

字符: 'a' 'A' '\n' 

字符串: "character string" 


三.常数 

在函数编程语言中, 函数是一个中心概念, 常数也可看作是常函数. 如下语句: 

f = 3 

定义了一个常数. f 被定义为3后就不能重复定义 f=5 ,任何时候调用f, 它都返回3. 这就消除了一些边际效应,减少了出错的可能性. 以下代码在函数编程和命令编程中具有完全不同的含义: 

a = 2 
b = 4 
c = a + b 

在函数编程中解释为: 定义常数a为2, 定义b为4, 定义c为a,b之和.   
在命令编程中解释为: 给变量a赋值2, 给b赋值4, 求a,b之和赋给c. 

定义和赋值的区别在于, 定义不分次序, 赋值有次序, 以上程序在Haskell中完全可以倒过来写: 

c = a + b 
a = 2 
b = 4 

另外, 定义并不计算, 比如: 

d = 3*5 
e = 1/0 

在命令程序中, e=1/0会引发一个错误, 在Haskell中只有当计算e时才引发错误. 

Haskell的思维更像是人脑的思维而不是机器的思维. 

也可以给常数加以类型说明, 比如: 

b :: Int 

如果没有这一类型说明, 系统自动根据 b=4 推断b的类型为: Integer 

Int和Integer区别是Int的取值范围是有限的, Integer的大小是无限的. 因为Integer比Int更普遍,所以在没有明显说明b的类型为Int时, 就自动推断b的类型为: Integer 

再举几个例子,在Haskell标准库Prelude中定义的常数中,有两个是: 

pi = 4 * atan 1 
otherwise = True 


四.单变量函数 

如下语句: 

f     (x)=x+2 
double(x)=2*x 

就定义了两个简单的函数, 函数的类型由自变量的类型和返回值在类型决定, 用运算符"->"连接. 

比如可以用以下语句说明它们的类型: 

f      :: Int -> Int 
double :: Float -> Float 

表示f是从Int变量到Int变量的映射. 如果没有明显说明, 系统根据函数定义中所涉及到的运算(+),(*)推断这两个函数的类型为:     

Num a => a -> a 

这里a是一个类型变量, 属于一个独立的名字空间, Num是一个类, Num a => 表示类型a属于Num类. Num类中定义了(+)和(*)的运算, 继承此类的类型也支持这两种运算. 这样使用类来限定函数的类型, 使函数具有的普遍性. 把类型归为一些类, 实现了类型的多态, 也简化了编程的任务. 

在Haskell中函数非常频繁地用到, 通常在函数的定义和使用中省去括号, 直接用两个标识符邻接表示函数作用. 所以f和double的定义可写为: 

f x      = x + 2 
double x = 2 * x 

调用函数的格式和定义函数的格式基本是相同的, 比如定义函数g如下: 

g x = 2 * f x 

函数作用的优先极高于其他所有的运算符, 所以2 * f x等价于2 * (f x), 也等价于2 * (f(x)). 

函数作用的次序是从左向右的, 所以可以等价地定义g为: 

g x = double (f x) 

Prelude有一个运算符$的定义如下: 
infixr 0  $ 
($)            :: (a -> b) -> a -> b 
f $ x           = f x 

可见, $也是表示函数作用的, 但它的优先级最低, 而且作用次序是从右向左的.所以还可以等价地定义g为: 

g x = double $ f x 

引入$, 避免了括号的使用, 尤其当$后的表达式很长有多行时使用$是很方便的. 


五. 多变量函数 


严格说来, 一个函数只能接收一个参数, 返回一个值. 但有两种方法可以实现多变量函数. 

1.Curried函数 

函数接受一个参数后, 返回的也是一个函数, 这个函数对可以接受别的参数. 比如: 

add :: Int -> Int -> Int 
add x y = x + y 

从add类型可以看出, 有两个"->", 而"->"的结合次序是从右向左, 所以add的类型是: 

Int -> ( Int -> Int ) 

即add接受一个Int参数, 返回一个( Int -> Int )的函数, 这个函数再接受一个Int返回一个Int. 

这样的函数就叫curried函数. 

2.使用数组 

数组就是把几个变量放到一起看成是一个变量, 从而使函数可以输入和输出多个变量. 比如: 

add :: (Int,Int) -> Int 
add (x,y) = x+y 

数组是Haskell中的一种数据结构, 数组中可以放不同类型的变量, 数目不限但长度固定, 数组的类型就是数组内各元素的类型组合起来构成一种类型. 

这两种函数在使用中各有特色, 而且可以用Prelude中定义的curry和uncurry互相转换. 

curry          :: ((a,b) -> c) -> (a -> b -> c) 
curry f x y     = f (x,y) 

uncurry        :: (a -> b -> c) -> ((a,b) -> c) 
uncurry f p     = f (fst p) (snd p) 

稍作一点解释:类型说明中出现的小写a,b,c等叫类型变量, 表示任意一种类型. f (x,y)表示f接受数组为参数, curry f x y就是(curry f) x y 表示curry f可以接受两个变量为参数. 令 g=curry f, 则 g x y = f (x,y). 可见curry的转换作用, curry的类型表达更清楚和说明了这一点. uncurry也是一样的道理, 其中的fst和snd分别表示取二元数组的第一个和第二个元素.定义如下: 

fst            :: (a,b) -> a 
fst (x,_)       = x 

snd            :: (a,b) -> b 
snd (_,y)       = y 

"_"叫匿名变量, 匹配指定类型任意的输入值, 该值在"="后的表达式中不会用到. 


六. 离散函数 

有些函数的参变量只有有限个取值, 比如Prelude中not的定义如下: 

not         :: Bool -> Bool 
not True     = False 
not False    = True 

not对逻辑变量取反. 

离散的变量可以使用保留字data定义, 比如: 

data Direction = Left|Up|Right|Down 

这就定义了一种Direction类型的变量, 这种变量的取值只有四个值:Left,Up,Right,Down. 

data定义了一个新的类型, type则可以给一个已有的类型取一个别名.比如: 

type Point = (Float, Float) 

(Float, Float)是容纳两个Float变量的数组的类型, 取别名后既简化了书写, 也附加了含义. 

现在看针对离散变量的函数如何定义: 

move :: Direction -> Point -> Point 
move Left  (x,y) = (x-1,y)         
move Up    (x,y) = (x,y-1) 
move Right (x,y) = (x+1,y) 
move Down  (x,y) = (x,y+1) 

即分别对应离散变量的每一个取值对函数作相应的定义. 以(x,y)表示位置, 给move输入移动的方向和当前的位置, 就输出了移动后的位置. 

再看一个例子: 

data Thing = Paper | Stone | Scissors   deriving Show 

beat :: Thing -> Thing 
beat Paper    = Scissors 
beat Stone    = Paper 
beat Scissors = Stone 

定义Thing类型有三个取值, deriving Show表示Thing类型继承Show类, 从而拥有的Show的method, Show类的作用是将取值转化为字符串在屏幕上显示. beat定义了三种物品,纸,石头,剪刀之间的输赢关系. 


自然数是离散的也是无限的, 以自然数为变量的函数通常用迭代的方法定义, 即函数自己调用自己.举个例子: 

fac 0 = 1 
fac n = n * fac (n-1) 

这样计算fac n时, 先去计算fac (n-1),有fac n = n * fac (n-1)=n * (n-1) * fac (n-2),如此类推, 一直算到fac 0, 最后的结果是把从1到n的自然数全部连乘起来. 

再比如:      
increment,fib :: Int -> Int 

increment x=x+1 

fib 1 = 1 
fib 2 = 2 
fib n = fib (n-1) + fib (n-2) 

当计算函数时, 按照输入的参数逐一匹配所给的模式, 如果无法匹配时给出错误中断. 对于自然数模式匹配还允许用如下方式定义函数: 
foo (n+1) = n-1 

Haskell中预定义的针对字符的函数有: 
isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, 
isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum, 
digitToInt, intToDigit, 
toUpper, toLower, 
ord, chr,等 

ord将字母转换为数字, chr反之. 



七. 连续函数 


Haskell中整数可以用Int和Integer表示, 实数可以用Float(单精度)和Double(双精度)来表示. 有理数还可用Rational表示, 相当于无限精度的浮点数. 
Prelude中定义了两个在数学上较基本的函数: 

1. 常数函数 

const          :: a -> b -> a 
const k _       = k 

2. 单位函数 

id             :: a -> a 
id    x         = x 

当函数针对变量的不同取值范围有不同的行为时, 就要用到选择结构. 比如: 

3. 绝对值函数 
abs' x = if x>=0 then x else -x     

if ... then ... else ...的结构也可以用"|"(guard)来表达, 上述abs'也可写成: 

abs' x |x>=0      = x 
|otherwise = -x   

"|"还可用于更多的分支选择, 比如: 
4. 符号函数 

sign x |x>0  = 1 
|x==0 = 0 
|x<0  = -1 

绝对值函数和符号函数在Prelude中分别为abs和signum, 其定义是用prime函数实现的. 
下面再举几例子,以熟悉函数的定义方法.                 

5. 二次方程求根函数: 

root (a,b,c) = (x1,x2) where         
x1=(-b+d)/(2*a) 
x2=(-b-d)/(2*a) 
dd = b*b-4*a*c 
d | dd>=0 =sqrt dd 
| dd<0  =error "No real root" 
这里where引入一个内嵌的语句块, 在其中定义的函数在外部是看不到的. error函数用来提示出错的信息. 

6. 求导函数 

diff :: (Float->Float) -> (Float->Float) 
diff f = f’ 
where f’ x = (f (x+h) - f x) / h 
h = 0.0001 
为了h的取值可调, 也可以把h包括在参数中: 
flexDiff h f x = (f(x+h)-f(x))/h 

把flexDiff h sin 1的取值和cos 1的取值在h=0.001,0.0001,0.00001下比较, 取0.0001的接近程度最好. 

7. 方程求根 
利用牛顿法可定义函数为: 
zero :: (Float->Float) -> Float 
zero f = until goodEnough improve 1.0 
where improve b = b - f b / diff f b 
goodEnough b = f b ~= 0.0 

其中until是Prelude中定义的执行循环的一个函数, 其定义如下: 

until          :: (a -> Bool) -> (a -> a) -> a -> a 
until p f x    = if p x then x else until p f (f x) 

until的作用是看条件p x是否成立, 不成立就用f作用x, 返回值替代原来的x, 直到条件p x成立为止. 

表示约等于的运算符~=则需要自己定义. 

8. 求逆函数 
利用方程求根的结果就可以求逆: 
inverse :: (Float->Float) -> Float -> Float 
inverse g a = zero f 
where f x = g x - a     


八. 数列和数组 

数列中元素的类型一致, 元素数目可变; 数组中元素的类型任意, 元素数目固定. 可以说数列和数组对数据的抽象做到了性能与灵活性的恰到好处, 有些语言中只提供一种容器, 元素数目可变, 类型也任意, 其结果是无法满足类型完全的需要, 也将低了运算的效率. 

数组的使用比较简单, 对于数列来说则大有文章. 

1. 数列的构造 

数列是用[]和(:)构造的, []是一个空的数列, x:xs的含义是元素x附加到数列xs的前面组成一个更长的数列. 比如, 1:[] 等于[1], 2:3:1:[]等于[2,3,1], 运算符(:)是从右向左运算的. 所有的数列都可以看作是从[]开始, 将各元素用(:)附到上面形成的. 在实际编程中有一些简记法可以快速地构造数列. 

a. 列举法 

将数列的元素一一列举, 比如: [1,2,3], ['A','B','d'], [[1,2], [4,5,6]]等等, 数列的类型用"[元素类型]"来表示, 这几个例子的类型依次为: [Int], [Char], {Int}. 

b. 给出变化范围 

适用于构造等差数列, 比如: [1..5]等于[1,2,3,4,5], ['a'..'d']等于['a','b','c','d']等于"abcd"因为type String=[Char]. 默认的等差为1, 也可以给出前两个元素指定等差, 比如: [2,4..8]等于[2,4,6,8], [2,4..7]等于[2,4,6], [2.5,4..9.5]等于[2.5,4.0,5.5,7.0,8.5,10.0]. 

c. 描述法 

描述法给出数列中元素取值的范围以及所满足的条件, 与数学中集合的描述法是一样的. 例如: 

[3*x+2| x<-[3,6,9]] --记号"<-"表示属于,x依次取3,6,9,代入3*x+2,得到数列[11,20,29] 
[x*x| x<-[1..9], x `rem` 3==1] --给出x的范围,还限定x除3余1 
[(x,y)|x<-[1,2,3],y<-[x..3]] --等于 [(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)] 

2. 从数列中选取元素 

head --数列的第一个元素 
tail --除去第一个元素剩余的数列 
last --最后一个元素 
init --除去最后一个元素剩余的数列 
take n --数列前n个元素 
drop n --除去数列前n个元素剩余的数列 
(!!)n  --第n个元素, 索引指标从0开始 

3. 从数列中筛选元素 

filter p    --把数列中所有满足条件p的元素取出来组成一个数列 
takeWhile p --从第0个元素起, 取满足p的元素, 遇到不满足条件的元素时停止 
dropWhile p --从第0个元素起, 去掉满足p的元素, 遇到不满足条件的元素时停止 

条件p是一个以数列元素为自变量, 返回值为逻辑值的函数. 比如预定义的even,odd判断奇偶性. 

4. 常用数列函数 

length lst --求数列的元素数目 
reverse lst --将数列中元素次序反过来 
lst1 ++ lst2 --将两个数列连成一个数列 
concat lst  --lst是数列的数列,concat将各子数列一个数列 

sum lst  --对lst中的元素求和 
product lst  --lst中的元素连乘 
elem e lst --判断e是否为lst中的元素 

or lst    --对类型为[Bool]的lst中所有元素求或 
and lst   --对类型为[Bool]的lst中所有元素求与 

zip 

5. 高阶函数 

map f lst --将lst按照函数f映射得到一个新的数列 
map :: (a->b) -> [a] -> 
map f [] = [] 
map f (x:xs) = f x : map f xs 

foldr,foldl --给定一种运算和一个初值,将初值和数列中所有元素由此运算连起来计算 
foldr :: (a->b->b) -> b -> [a] -> b 
foldr op e [] = e 
foldr op e (x:xs) = x ‘op‘ foldr op e xs 

foldl op e [] = e 
foldl op e (x:xs) = foldl op (e‘op‘x) xs       

示例: 

rate   :: [Float]->[Float]                   
rate ls = map (/s) ls where s=sum ls    

--(/s)是将运算符"/"偏参化,并括起来当作函数使用    

numDigits [] = 0 
numDigits (c:cs) = (if (c >= '0') && (c <= '9') then 1 else 0) + numDigits cs 

--典型的以模式匹配和迭代的方法定义数列函数, numDigits 计算字符串中数字的个数 


九. 无限数列 

可以定义无限长的数列, 比如: 
from :: Int -> [Int] 
from n = n : from (n+1) 

from2 = from 2     

from n得到的是一个从n开始的无限长的自然数列, 因为Haskell的lazy evaluate或non-strict的特性, 这个定义并不会引起无限次的计算. 对数列进行操作时, 有的函数要用到数列中所有的元素, 用这样的函数操作无限数列就会使计算机不停地计算, 直到内存或堆栈不够用为止; 而有的函数只用到数列的一部分元素, 这时无限数列就派上用场了. 比如: 

take 5 from2 => [2,3,4,5,6] 
from2(!!)9   => 11 
takeWhile (\x->x*x<100) from2 => [2,3,4,5,6,7,8,9] 

这里用"=>"表示计算结果, (\x->x*x<100) 是一个匿名函数,即用这样的格式表达了函数的输入与输出却不用给函数起名字另行定义. 

上述from函数其实可以用给出数列元素变化范围的方法直接得到数列, 比如: [2..], [1,3..] 
Prelude中定义用于生成无限数列的函数还有: 
repeat :: a -> [a] 
repeat x = x : repeat x    --对元素a无限重复 

iterate :: (a->a) -> a -> [a] 
iterate f x = x : iterate f (f x) 
{- 
iterate (+1) 3 is [3, 4, 5, 6, 7, 8, . . . 
iterate (*2) 1 is [1, 2, 4, 8, 16, 32, . . . 
iterate (/10) 5678 is [5678, 567, 56, 5, 0, 0, . . . 
-} 
下面再举几个无限数列的应用的例子: 

squares = [ x*x | x<-[0..]] 
isSquare n = elem n (takeWhile (<=n) squares)   --判断一个数是否为平方数 

fibs = fibgen 1 1   --Fibonacci 数列 
fibgen n1 n2 = n1 : fibgen n2 (n1+n2) 

primes = map head (iterate crossout [2..])      --用筛法求素数   
where  crossout (x:xs)=filter (not.divisible x) xs 
divisible x y = y `rem` x == 0 

prime = sieve [2..]         ---改进后的素数数列 
sieve (x:xs) = x : sieve (filter (\y ->y `rem` x /= 0) xs) 

有了这些定义后, take 100 prime 就是取前100个素数, prime(!!)1000 就是取第1000个素数, 因为数列的定义是无限的, 数列的计算是有限, 这样就无须为不同的需要定义不同长度的数列, Hakell处理无限数列的能力实在是令人叹服. 


十. 数列排序 

Qucik Sort是对数列元素快速排序的一种算法. 初次见到的版本是: 

qsort1 []     = [] 
qsort1 (x:xs) = qsort1 elts_lt_x ++ [x] ++ qsort1 elts_greq_x 
where 
elts_lt_x   = [y | y <- xs, y < x] 
elts_greq_x = [y | y <- xs, y >= x] 

后来又有人将其写为: 

qsort2 [] = [] 
qsort2 (x:xs) = qsort2 less ++ [x] ++ qsort2 more 
where less = filter   (<x)  xs 
more = filter   (>=x) xs 

可以明显地看到在比较的过程中对数列扫描的两次, 所以我就想能不能扫描一次就把比x大的和比x小的分开, 这就是我的第一个实现这一想法的程序: 

qsort3 [] = [] 
qsort3 (x:xs) = qsort3 xl ++ [x] ++ qsort3 xr 
where  (xl,xr,_) = until f g ([],[],xs) 
f (_,_,w)=w==[] 
g (l,g,y:ys) |y<=x =(y:l,g,ys) 
|y> x =(l,y:g,ys) 


但这个程序的效率不高, 然后就逐渐改进: 

qsort4 []=[] 
qsort4 (x:xs)=qsort4 xl ++ [x] ++ qsort3 xr 
where (xl,xr)=split (<x) xs 
split f []=([],[]) 
split f (y:ys) |f y  =(y:fst (split f ys),snd (split f ys)) 
|True =(fst (split f ys),y:snd (split f ys))     


qsort5 []=[] 
qsort5 (x:xs)=qsort5 xl ++ [x] ++ qsort5 xr 
where (xl,xr)=split (<x) xs 
split f []=([],[]) 
split f (y:ys) |f y  =(y:l,r) 
|True =(l,y:r) 
where (l,r)=split f ys                                                             

qsort6 []=[] 
qsort6 (x:xs)=qsort6 xl ++ [x] ++ qsort6 xr 
where (xl,xr)=split x xs 
split _ [] = ([],[]) 
split e (x:xs) | e>=x  = (x:l,r) 
| e<x   = (l,x:r) 
where (l,r) = split e xs 

qsort7 []=[] 
qsort7 (x:xs)=qsort7 xl ++ [x] ++ qsort7 xr 
where (xl,xr)=split x xs 
split _ [] = ([],[]) 
split e (x:xs) | x<e   = (x:l,r) 
| True  = (l,x:r) 
where (l,r) = split e xs 


qsort8 []=[] 
qsort8 (x:xs)=qsort8 xl ++ (x: qsort8 xr) 
where (xl,xr)=split x xs 
split _ [] = ([],[]) 
split e (x:xs) | x<e   = (x:l,r) 
| True  = (l,x:r) 
where (l,r) = split e xs                            



qsort9 ls  = qsort' ls [] 
where  qsort' []     acc = acc 
qsort' (x:xs) acc = qsort' xl (x:qsort' xr acc) 
where (xl,xr) = split x xs 
split _ [] = ([],[]) 
split e (x:xs) | x<e   = (x:l,r) 
| True  = (l,x:r) 
where (l,r) = split e xs                            


qsort10 ls = qsort' ls [] 
where  qsort' []     acc = acc 
qsort' (x:xs) acc = split x xs [] [] acc 
where split e [] l r acc = qsort' l (e:qsort' r acc) 
split e (x:xs) l r acc | x<e  = split e xs (x:l) r acc 
| True = split e xs l (x:r) acc     


qsort6 对算法的体现最直接, 最容易理解. 以后每一次改动都是为了提高程序运算的效率. 

尽管qsort10已经排得很快了, 但 merge sort 可以排得更快. 

msort:: Ord a => [a] -> [a] 
msort = treefold merge [] . map (:[]) 

merge:: Ord a => [a] -> [a] -> [a] 
merge [] b = b 
merge a [] = a 
merge (a:a's) (b:b's) 
| a < b = a: merge a's (b:b's) 
| otherwise = b: merge (a:a's) b's 

为了进行检验, 在源文件最开始加入: 

import Random 
gen=mkStdGen 60 
lst=take 100 (randomRs (1,100) gen ::[Int])   

生成一个包含100个随机数的数列lst.      


十一. 排列组合 

排列是把数列的元素的所有可能的排列次序都找出来. 

perms :: [a] -> {a} 
perms [] = [ [] ] 
perms (x:xs) = concat (map (between x) (perms xs)) 
where between e [] = [ [e] ] 
between e (y:ys) = (e:y:ys) : map (y:) (between e ys)   

组合是从数列中取若干个元素所有可能的取法. 

combs :: Int -> [a] -> {a} 
combs 0 xs = [ [] ] 
combs (n+1) [] = [ ] 
combs (n+1) (x:xs) = map (x:) (combs n xs) ++ combs (n+1) xs 

这两个算法都是从书上找的. 以下的程序是我自己写的: 

maps :: [a->b]-> a -> 
maps [] x = [] 
maps (f:fs) x = f x : maps fs x 

split :: Int -> [a] -> ([a],[a]) 
split 0 ls = ([],ls) 
split _ [] = ([],[]) 
split n (x:xs) = (x:xl,xr) 
where (xl,xr)=split (n-1) xs    

perm :: [a]->{a} 
perm [] = [[]] 
perm lst = concat $ maps fs lst 
where fs = map f [0..length lst-1] 
f i lst = map (x:) (perm (xl++xs) ) 
where (xl,xr)=split i lst 
(x:xs)=xr 


maps和map的定义非常类似, 执行类似其他语言中for循环的功能, 而until执行while循环的功能. 

split将数列分成两个部分, 前半部分包括n个元素, 后半部分为剩余的元素. 

perm计算的效率虽不太高, 但是 

perm [1,2,3] 

输出的结果为:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 
跟自己手工排的结果是一样的. 而 

perms [1,2,3] 

输出的结果为:[[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]] 
看起来有点乱. 

后来对perm改进得: 

sp xl [x] = [(xl,x,[])]   
sp xl (x:xr) = (xl,x,xr):sp (xl++[x]) xr 


perm' [x]={x} 
perm' ls= [x:xs|(xl,x,xr)<-sp [] ls, xs<-perm'(xl++xr) ]   

perm'同perm所用的算法和思路是一样的, 但效率已大大提高了. 




十二. 运算符 

定义一个运算符, 要说明它的结合性和优先级. 

infixr 右结合 
infixl 左结合 
infix  不结合 

左右都可结合的运算符如 +, * 定义为左结合即可. 
优先级从0到9, 0最低, 9最高 

已定义的运算符有: 

level 9 . and !! 
level 8 ^ 
level 7 *, /, `div`, `rem` and `mod` 
level 6 + and - 
level 5 :, ++ and \ 
level 4 ==, /=,<, <=, >, >=, `elem` and `notElem` 
level 3 && 
level 2 || 
level 1 (not used in the prelude) 

举例:     

infixr 3  &&                        
(&&)  :: Bool -> Bool -> Bool 
False && x   = False 
True  && x   = x          

先定义&&的结合性和优先级, 然后象定义函数一样定义它的功能. 

运算符用括号括起来, 可以当作函数使用, 比如: 

map (3+) [1,2,3] 

map (+3) [1,2,3] 

函数名用左引号`引起来, 也可以声明为运算符, 比如: 

fac n = product [1..n] 

infix 5 !^!, `choose` 
(!^!), choose :: Int->Int->Int                    
n `choose` k = fac n `div` (fac k * fac (n-k)) 
n !^! k = fac n `div` (fac k * fac (n-k))      

有了这些定义后, 

choose 5 2 
(!^!)  5 2 
5   !^!  2 
5 `choose` 2 

都给出答案10.   


十三. 复合函数 


当一个函数的返回值的类型与另一个函数输入值的类型相同时, 这两个函数就可以复合. 在Haskell中两个函数复合用运算符(.)表示. 举几个例子: 

f x = (x,2) 
g (x,y)=(x+y)*(x-y) 
h = g.f 

sumaux []=[] 
sumaux (x:xs)=x+sum xs : sumaux xs 
sums =reverse.sumaux.reverse 

函数复合也可以使用匿名函数, 比如: 

foo=not.(\x->even x && x<100) 

复合运算满足结合律: 

f . (g . h) = (f . g) . h 

下面看几个定理: 

(map f . map g) xs = map (f.g) xs 即 map f . map g = map (f.g) 

map f (xs++ys) = map f xs ++ map f ys 

map f . concat = concat . map (map f) 

map f . (x:) = (f x :) . map f 

map f xs = foldr g [] ys where g x ys = f x : ys 

concat xss = fold (++) [] xss 

length . combs k = ( `choose` k) . length 

sum (xs++ys) = sum xs + sum ys 


这些定理都不难理解, 也很容易证明. 你也可以自己证明一些其他的定理. 


十四. 小结 

从前面各节的标题来看, Haskell根本就是在搞数学, 不象是在编程. 其实这正体现了Haskell的一个突出的优点, 它对各种数学概念提供了完美的支持, 我说Haskell是数学家的乐园. 数学是一个基础, 我认为把数学做好的编程语言才有潜力把其他事情做好. 

你在作数学题的时候, 从来也没有过把变量看作是存储器, 给变量赋值的概念, 也没有用到for,while循环语句, 而在Haskell中正好抛弃了这些概念. 用Haskell解决问题的思路与人思路非常接近, 比如相当一部分函数以数学归纳法的方式来定义, 对数据的描述性的定义等. 它掩盖了非常细节的问题, 在更高的层次上处理问题. 这样就提高了编程的效率, 提高了代码的可重用性. 

Haskell是世界上公认的语法最优美最简洁的一种语言。Haskell语言是写给人看的,而不是写给机器看的。另一方面,这也使得的Haskell的编译技术成为一个难点, 编译后的程序运行速度比C略慢一些。从以人为本的角度来看,程序员的时间比机器的时间更宝贵,所以Haskell是明智的选择。    

以后各节将更多关注于Haskell编程方面的一些特性, 而不仅仅是做算术. Haskell的高效和强大将得到进一步的证实. 由于Haskell主要是在UNIX平台上发展起来的, 专门针对Windows的类库不是很多. 但Haskell的先进性是不容置疑的, 它的发展只是一个时间的问题. 

我希望你们已经意识到为什么要学函数编程语言, 欢迎来到精彩的Haskell世界--一个更好的地方. 


十五. 输入输出 


1.输出字符串: putChar, putStr, putStrLn, print, 
输入字符串: getChar, getLine, getContents, interact, 

2.文件操作: readFile, writeFile, appendFile, readIO, readLn   


GHC使用指南 

GHC可以把Haskell程序编译为可执行文件. 操作方法如下: 

1.到http://www.haskell.org/ghc/下载并安装GHC. 
2.用cmd打开一个命令窗口. 
3.输入ghc --make file.hs 回车. 
ghc为编译器, 必要时给出ghc.exe文件所在的目录, file.hs为被编译的文件, 必要时也 
给出它的目录. 
file.hs文件中要包含一个函数名为main的函数,运行可执行文件时这个函数被执行. 
4.输出文件的文件名为a.out, 将后缀名改为exe, 就可以运行了. 
5. 使用ghc -o foo file.hs 可以指定输出文件名, 在此例中将得到foo.exe 
使用ghc -O file.hs     可以优化编译输出 
6. 当源程序中使用了某个或多个package时,使用 
ghc -package p_name1 -package p_name2 --make file.hs 
加载所需的包. 
7. 使用ghc --interactive 可以打开ghci, 在ghci中使用:set -package name 加载包


转自:http://www.cnblogs.com/erain/archive/2008/12/17/1357175.html


查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. linux-格式化

    文件系统支持查看Linux支持的文件系统cat /proc/filesystems这个列举出来的并不就是全部能够支持的全部文件系统类型。 VFS基本涵盖了全部的文件系统,只是支持的程度问题。 不过是代码级别的支持,编译之后,可能会删减一些,所以这个看到的就是删减之后能支持的了。 想要支持…...

    2024/4/24 23:36:44
  2. ASP.NETmvc5下使用DropDownList的使用 ,和asp.net里的DropDownList控件的方法

    前台页面后台代码 用LINQ写的S_ID = u1.CI_ID, S_Name = u1.CI_Name相当于dataTextFileld 和dataValueField...

    2024/5/1 7:40:11
  3. echart显示自定义图标

    可以通过矢量图标实现自定义需求 实现方式 在阿里图标中找到想要的图标,然后将svg改为矢量图标 <svg t="1592984597912" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id…...

    2024/4/24 23:36:40
  4. [原创]自己动手写博客园博文提取器,提取文件保存支持PDF、doc、txt三种格式

    下载地址http://download.csdn.net/detail/w397090770/4443454同样是免积分的 前几天发了一个[原创]自己动手写CSDN博客提取器,提取文件保存支持PDF、doc、txt三种格式 飞程序,有网友反映要做一个可以提取博客园博文,今天我分析了一些博客园的网站,做了一个相似的博客园博…...

    2024/5/1 12:37:24
  5. @Html.DropDownList()的四种用法及自定义DropDownList扩展

    常用方法后台代码:public ActionResult Index() {ViewData["deptOu"] = "SOHO";using (ISession session = new NHibernateHelper(DataBase.ADDB).OpenSession()){IList<t_data_DeptOU> deptOuList = session.QueryOver<t_data_DeptOU>().Lis…...

    2024/5/1 9:23:00
  6. Linux格式化命令

    如果我们购买一个新的虚拟主机空间或者要更改操作程序,会经常使用到磁盘格式化来清空以前的数据,磁盘格式化的方法很多,我们常用的是NTFS和linux格式化命令两种方法来格式化磁盘,我们讲解一下linux格式化命令的详情。linux格式化磁盘命令linux mkfs指令:mkfs使用权限 : 超…...

    2024/5/1 11:21:34
  7. C++Builder/Delphi XE2 UniDAC安装教程

    C++Builder/Delphi XE2 UniDAC安装教程 UniDAC是一个功能强大的非可视化跨数据库的数据访问组件,可用于Delphi,Delphi for .NET,C++Builder,and Lazarus (Free Pascal)。它提供了对流行数据库服务器的统一访问,像Oracle,Microsoft SQL Server,MySQL,InterBase,Firebi…...

    2024/5/1 6:24:40
  8. 新浪博客关闭了吗,不能写博文了,提示:系统繁忙,请稍后再试

    新浪博客关闭了吗,不能写博文了,提示:系统繁忙,请稍后再试。 不知道你们大家有没有一直是这样,我从去年开始发现就一直是这样的,最近几天基本上每天分不同的时间段去测试,还是发不了文。 不信你们看看我的博客,http://blog.sina.com.cn/u/5899195590 一直是空的,什么都…...

    2024/4/28 13:15:34
  9. 百度Apollo5.5与LGSVL模拟器进行连接

    百度Apollo5.5的安装教程请参考我的另一篇Blog。Apollo5.5安装教程 安装之后,建立Apollo的桥接模块:bash scripts/bootstrap_lgsvl.sh bash scripts/bridge.sh # 执行之后,terminal没有任何输出,应该是一直在等待模拟器的数据 在浏览器中打开Dreamview(http://localhost:8…...

    2024/4/24 23:36:36
  10. RabbitMQ的简单用法

    这里主要是讲解的将一条消息放入mq中,然后在mq中进行处理, 生产者: 第一步:创建Queue名: public class ConstantMqName {//查询记录队列public static final String MQ_RECORD_SEARCH_CONTENT= "mq-record-search-content"; }import com.hisi.ie.common.constan…...

    2024/4/28 8:33:33
  11. 声学的一些基本知识(心理声学)

    心理声学(psycho acoustics)是研究声音和它引起的听觉之间关系的一门学科。人耳对声音的感知是高度非线性了。由于人耳听觉系统复杂,人类迄今为止对它的机理和听觉特性的某些问题还不能从生理解剖角度完全解释清楚。所以,就出现了心里声学这一在心理声学和语言声学内对对人耳…...

    2024/4/14 21:05:25
  12. 重装系统后快速恢复hexo博客(保留了原有的博客文件夹)

    前言本人刚假期结束回到宿舍。。发现自己的电脑外设全都没有了反应,重装驱动也不行,于是就只能重装系统了重装系统后发现博客的环境又得重新配置,我就简单记录一下正文首先我把git跟Node还有hexo重装了一遍, 因为重装系统有可能删除了配置文件包括环境变量里面的,没有配置…...

    2024/4/19 13:22:54
  13. ROS机器人编程新书推荐(附免费下载)

    来源网站一本新的ROS书籍:“ROS机器人编程,由TurtleBot3开发人员编写”。 现在,这本书已经出版了英文和中文版本。 你可以下载这本书的pdf。本书的作者想要感谢Morgan、Tully、OpenRobotics的Brian以及所有ROS开发团队、维护者和贡献者。 这本书是对所有ROS社区成员表示感谢…...

    2024/4/29 1:20:59
  14. 怎么设置asp.net中DropDownList下拉列表的高度?

    怎么设置asp.net中DropDownList下拉列表的高度? 转载于:https://www.cnblogs.com/HeroBeast/archive/2007/07/11/814441.html...

    2024/4/14 21:05:21
  15. ARM学习笔记(二)

    嵌入式处理器分类 目前的嵌入嵌入式处理器按其体系结构不同可分为五大类:  ARM(Advance RISC Machine)  MIPS  POWER PC  X86  SH系列ARM体系结构的版本(V1-V6) 每一个ARM处理器都有一个特定的指令集架构ISA(Instruction Set Architecture),每一个ISA版本可以有多种…...

    2024/4/26 23:19:05
  16. Linux格式化硬盘 常用命令小记

    今天新蛋上订购了一块1TB的硬盘打算装Ubuntu,当然先要做好功课,查一下注意事项啦! 基本功,格式化命令,以格式化 /dev/sda1 分区为例:$ sudo umount /dev/sda1 # 必须先卸载该分区 # 格式化为 FAT 分区$ sudo mkfs.vfat -F 32 /dev/sda1 # -F 参数必须大写,参数…...

    2024/4/14 21:05:19
  17. MYSQL学习教程总结

    `students`#进阶1: 基础查询 /* 语法: select 查询列表 from 表名; 类似于:System.out.println(打印东西); 特点: 1、查询列表可以是:表中的字段、常量值、表达式、函数 2、查询的结果是一个虚拟的表格 */ USE `myemployees`; #1查询单个字段 SELECT last_name FROM emplo…...

    2024/4/29 23:43:05
  18. idea tomcat 乱码问题的解决

    问题,在idea中出现乱码问题,以前没有的,好像在设置系统代码为utf8之后就出现了,于是尝试了一系列办法,希望这些办法对您有帮助。先看一下乱码的样式。设置办法1、在tomcat Server中设置 VM options , 值为 -Dfile.encoding=UTF-8 ,可惜没生效12、在setting中的 File enco…...

    2024/4/24 23:36:33
  19. 【ARM学习笔记】实验一:S3C2440A的GPIO输出实验

    GPIO引脚的主要作用输出/输入高低电平,用来表示二进制的0和1,当然除此之外还有其它特殊功能,这在之后的课程会学习到的,此处只需要研究输出功能。实验1:在下面的电路中:如果想要点亮4个LED,应该怎么做呢【原理】需要让适宜的电流从右到左通过LED,这样才能激发LED发光【…...

    2024/4/24 23:36:32
  20. EasyUI + Select2 3.4 用法

    非常好用的组件,效果如下:步骤:引入js,css<link href="3.4/select2.css" rel="stylesheet" /> <script src="3.4/select2.min.js" type="text/javascript"></script>页面预算 注意:新版(4.0+)的绑定标签必须是…...

    2024/4/29 20:12:05

最新文章

  1. 第11章 数据库技术(第一部分)

    一、数据库技术术语 &#xff08;一&#xff09;术语 1、数据 数据描述事物的符号描述一个对象所用的标识&#xff0c;可以文字、图形、图像、语言等等 2、信息 现实世界对事物状态变化的反馈。可感知、可存储、可加工、可再生。数据是信息的表现形式和载体&#xff0c;信…...

    2024/5/1 14:49:40
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 【LeetCode热题100】【二叉树】二叉树的中序遍历

    题目链接&#xff1a;94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 中序遍历就是先遍历左子树再遍历根最后遍历右子树 class Solution { public:void traverse(TreeNode *root) {if (!root)return;traverse(root->left);ans.push_back(root->val);tra…...

    2024/4/29 11:15:33
  4. 数据挖掘中的PCA和KMeans:Airbnb房源案例研究

    目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…...

    2024/5/1 13:14:26
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/29 23:16:47
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/30 18:21:48
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/30 9:43:22
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57