通过添加元素修改当前列表 - Haskell 101

时间:2017-11-09 13:04:02

标签: list haskell immutability

我想在名为Director的数据类型billy变量的“电影”列表中添加一个元素。

type Name  = String
type Movie = String
data Director = Director {name:: Name, movies::[Movie]}
    deriving (Show)
let billy = Director "Billy J." ["Good movie 1"]

--addMovieToDirector :: Movie -> Director -> Director
addMovieToDirector m (Director n ms) = Director n (m:ms)

问题是以前的功能没有更新比利的电影列表,它会创建一个带有所需列表的新Director(更改不存储在比利上)。如何在不创建另一个Director的情况下在比利的列表上操作?我理解,Haskell使用常量,但是每次修改列表时我应该创建一个不同的'billy'“变量”吗?

谢谢!

2 个答案:

答案 0 :(得分:7)

您想要做的是“就地修改”或“使用可变数据”。

Haskell有很多方法可以做到这一点。由于任何事物的就地修改几乎总是被视为“副作用”,因此这些事情只能在IO monad中完成,或者使用像unsafePerformIO这样的诡计。

这些是一些高级主题,在初学者层面上,将Haskell值视为完全不可变是有益的。

所以是的,你无法修改变量。实际上根本没有“变量”。

billy视为值的名称,而不是变量。

Haskell中的所有函数都可以接受参数,并计算一些没有任何副作用的结果

对于来自命令式语言的人来说,这可能是最大的心理障碍:“如果我无法修改数据,我该如何处理数据?”

答案是:您应该像巨型装配线一样构建您的程序:原材料(原始数据,初始参数等)在开头(您调用的第一个函数)和每个工作站(函数)上线)做一些有用的东西(返回一个值),消耗前一个工作站的结果。最后,有价值的东西可能会脱离生产线。

我所描述的是简单的功能组合:如果您需要在c之后,b之后,在值a上执行x任务,那么您可以编写它为(c . b . a) x,或c (b (a x))或更确切地说c $ b $ a x

通过这种方式,您可以编写程序而无需明确地更改任何内容,并且只描述如何使用旧内容创建新内容。

这听起来非常低效,事实上,功能编程有一些性能影响(更不用说懒惰)了。然而,编译器足够聪明,能够弄清楚用Haskell编写的程序,并以某种方式对其进行优化。

我希望很快就会有意义。 :)

哦,欢迎来到Haskell。 ;)

答案 1 :(得分:0)

如果您希望程序中存在可变状态,则可以使用State monad。这是一个例子:

module Main where

import Control.Monad.State

type GameValue = Int
type GameState = (Bool, Int)

type Name  = String
type Movie = String
data Director = Director {name:: Name, movies::[Movie]}
    deriving (Show)

addMovieToDirector :: Movie -> Director -> Director
addMovieToDirector m (Director n ms) = Director n (m:ms)


handleDirector :: Name -> State Director Director
handleDirector m = do
    director <- get
    put (addMovieToDirector m director)
    returnDirector

returnDirector = do
    director <- get
    return director

startState = Director "Billy J." ["Good movie 1"]

main = print $ evalState (handleDirector "Good movie 2") startState

打印结果将是

  

导演{name =&#34; Billy J。&#34;,movies = [&#34; Good movie 2&#34;,&#34; Good movie 1&#34;]}

此类handleDirector类型Name -> State Director Director函数在Director类型中具有可变状态,而#34;结果&#34;类型的值,再次,Directorget表示获取状态,put用于更改状态,evalstate用于&#34;计算&#34;结果,由构造的State monad包围。