Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell:从程序中的多个位置追加到列表_Haskell_Functional Programming_Global Variables_Memoization - Fatal编程技术网

Haskell:从程序中的多个位置追加到列表

Haskell:从程序中的多个位置追加到列表,haskell,functional-programming,global-variables,memoization,Haskell,Functional Programming,Global Variables,Memoization,我想有一个列表,可以从代码中的多个位置更新(附加到)。在haskell,如果不允许出现副作用,我管理这个列表的最佳方式是什么?我曾想过每次需要附加列表时都要将列表传递给它,但我不知道这是否足以完成我想要完成的任务。使用Memorization[编辑非动态规划]并在助手列表中存储可能的最佳赢款列表。使用单子和状态模拟全局变量是一个好主意还是有更好的方法 编辑:这是我在python中实现它的方式: def BJ(i):

我想有一个列表,可以从代码中的多个位置更新(附加到)。在haskell,如果不允许出现副作用,我管理这个列表的最佳方式是什么?我曾想过每次需要附加列表时都要将列表传递给它,但我不知道这是否足以完成我想要完成的任务。使用Memorization[编辑非动态规划]并在助手列表中存储可能的最佳赢款列表。使用单子和状态模拟全局变量是一个好主意还是有更好的方法

编辑:这是我在python中实现它的方式:

def BJ(i):                                                                                                                                                                                                  
    if i in BJList:                                                                                                                                                                                         
        return BJList[i]                                                                                                                                                                                    
    else:                                                                                                                                                                                                   
        options = [0]                                   # if you walk away                                                                                                                                  
        if n-i < 4:                                     # not enough cards to play                                                                                                                          
            return 0                                                                                                                                                                                        
        for p in range(2,(n - i)):                      # number of cards taken                                                                                                                             
            player = c[i] + c[i+2] + sum(c[i+4:i+p+2])                                                                                                                                                      
            # when p is 2                                                                                                                                                                                   
            if player > 21:                                                                                                                                                                                 
                options.append(-1 + BJ(i + p + 2))                                                                                                                                                          
                break                                   # breaks out of for(p)                                                                                                                              
            dealer = 0                                                                                                                                                                                      
            d1 = 0                                                                                                                                                                                          
            for d in range(2,n-i-p+1): # python ranges are not inclusive                                                                                                                                    
                d1 = d                                                                                                                                                                                      
                dealer = c[i+1] + c[i+3] + sum(c[i+p+2:i+p+d])                                                                                                                                              
                if dealer >= 17:                                                                                                                                                                            
                    break                               # breaks out of for(d)                                                                                                                              
            if dealer < 17 and i + p + d >= n:          # doesn't change results, maybe                                                                                                                     
                dealer = 21                             # make it be more like haskell version                                                                                                              
            if dealer > 21:                                                                                                                                                                                 
                dealer = 0                                                                                                                                                                                  
            dealer += .5                                # dealer always wins in a tie                                                                                                                       
            options.append(cmp(player, dealer) + BJ(i + p + d1))                                                                                                                                            
        BJList[i] = (max(options))                                                                                                                                                                          
        return max(options)                                                                                                                                                                                 

c = [10,3,5,7,5,2,8,9,3,4,7,5,2,1,5,8,7,6,2,4,3,8,6,2,3,3,3,4,9,10,2,3,4,5]                                                                                                                                 
BJList = {}                                                                                                                                                                                                 
n = len(c)                                                                                                                                                                                                  
print "array:" +  str(c)                                                                                                                                                                                    
print BJ(0)  

如果我没弄错的话,你是在处理相对较短的名单,因为只有52张卡片。所以我会保持简单,编写函数,将列表作为输入,并将更新后的列表作为输出返回

我只是浏览了一下您的python代码,所以下面提供的示例可能并不完全符合您的需要,但至少它会给您一个想法。假设您想用新卡替换手牌中的第三张卡。你可以用这样的东西
replaceElement xs n x
返回
xs
的副本,其中
n
th元素已替换为
x

replaceElement :: [a] -> Int -> a -> [a]
replaceElement xs i x = 
  if 0 <= i && i < length xs then fore ++ (x : aft) else xs
  where fore = take i xs
        aft = drop (i+1) xs

如果你处理的是大列表,我建议你看看可变列表,也许还有状态单子等等。但是当我还是Haskell初学者的时候,我最常犯的错误就是把事情复杂化了。我创建了太多的类和类型,使用了过多的单子,等等。

如果我正确理解了这个问题,您处理的是相对较短的列表,因为只有52张卡。所以我会保持简单,编写函数,将列表作为输入,并将更新后的列表作为输出返回

我只是浏览了一下您的python代码,所以下面提供的示例可能并不完全符合您的需要,但至少它会给您一个想法。假设您想用新卡替换手牌中的第三张卡。你可以用这样的东西
replaceElement xs n x
返回
xs
的副本,其中
n
th元素已替换为
x

replaceElement :: [a] -> Int -> a -> [a]
replaceElement xs i x = 
  if 0 <= i && i < length xs then fore ++ (x : aft) else xs
  where fore = take i xs
        aft = drop (i+1) xs

如果你处理的是大列表,我建议你看看可变列表,也许还有状态单子等等。但是当我还是Haskell初学者的时候,我最常犯的错误就是把事情复杂化了。我创建了太多的类和类型,使用了过多的单子,等等。

一般来说,我看到3种解决方案,对Haskeller的“吸引力”越来越小:

  • 以纯函数的方式编写算法

    • 优点:没有副作用,很漂亮
    • 缺点:如果是命令式的,你可能需要重写算法(这里就是这种情况)
  • 使用
    State
    monad模拟State,因为它实际上只是“隐藏”函数的附加参数

    • 赞成:命令式感觉
    • 缺点:一元代码,通常更难推理,也不容易重用
    • 例如:

      workerState :: State [Int] ()
      workerState = do
        modify (++ [21])
        {- lots of stuff happening -}
        modify (++ [21])
      
      -- E.g. in repl
      > runState workerState []
      
      workerST :: STRef s [Int] -> ST s ()
      workerST ref = do
        modifySTRef ref (++ [21])
        {- lots of stuff happening -}
        modifySTRef ref (++ [21])
      
      -- E.g. in repl:
      > runST $ do
          r <- newSTRef []
          workerST r
      
  • 使用副作用。这意味着使用
    ST
    monad或某种可变引用,如
    IORef

    • 优点:真正的易变性,由于一元风格,对原始算法的更改最小
    • 缺点:都来自
      状态
      +终极邪恶:副作用
    • 例如:

      workerState :: State [Int] ()
      workerState = do
        modify (++ [21])
        {- lots of stuff happening -}
        modify (++ [21])
      
      -- E.g. in repl
      > runState workerState []
      
      workerST :: STRef s [Int] -> ST s ()
      workerST ref = do
        modifySTRef ref (++ [21])
        {- lots of stuff happening -}
        modifySTRef ref (++ [21])
      
      -- E.g. in repl:
      > runST $ do
          r <- newSTRef []
          workerST r
      

      总的来说,我看到3种解决方案,对Haskellers的“吸引力”有所下降:

    • 以纯函数的方式编写算法

      • 优点:没有副作用,很漂亮
      • 缺点:如果是命令式的,你可能需要重写算法(这里就是这种情况)
    • 使用
      State
      monad模拟State,因为它实际上只是“隐藏”函数的附加参数

      • 赞成:命令式感觉
      • 缺点:一元代码,通常更难推理,也不容易重用
      • 例如:

        workerState :: State [Int] ()
        workerState = do
          modify (++ [21])
          {- lots of stuff happening -}
          modify (++ [21])
        
        -- E.g. in repl
        > runState workerState []
        
        workerST :: STRef s [Int] -> ST s ()
        workerST ref = do
          modifySTRef ref (++ [21])
          {- lots of stuff happening -}
          modifySTRef ref (++ [21])
        
        -- E.g. in repl:
        > runST $ do
            r <- newSTRef []
            workerST r
        
    • 使用副作用。这意味着使用
      ST
      monad或某种可变引用,如
      IORef

      • 优点:真正的易变性,由于一元风格,对原始算法的更改最小
      • 缺点:都来自
        状态
        +终极邪恶:副作用
      • 例如:

        workerState :: State [Int] ()
        workerState = do
          modify (++ [21])
          {- lots of stuff happening -}
          modify (++ [21])
        
        -- E.g. in repl
        > runState workerState []
        
        workerST :: STRef s [Int] -> ST s ()
        workerST ref = do
          modifySTRef ref (++ [21])
          {- lots of stuff happening -}
          modifySTRef ref (++ [21])
        
        -- E.g. in repl:
        > runST $ do
            r <- newSTRef []
            workerST r
        

        以下是如何以更实用的方式思考
        BJ
        过程:

        p
        的每个值都向
        options
        列表添加一个元素,因此您可以将
        options
        视为具有以下定义:

        options = map f [2..n-i-1]
        
        其中,
        f
        是一个有待确定的函数

        对于
        p
        的每个值,我们需要确定以下内容:

        • 运动员的计数
        • 经销商们算了算
        • 所取卡片的数量
        因此,这建议我们应该编写一个函数,如下所示:

        result :: Int -> (Int,Int,Int) -- player's count, dealers count, cards taken
        result p = ...
        
        现在我们可以这样表达
        选项

        options = map score (map result [2..n-i-1])
        
        score :: (Int,Int,Int) -> Int
        score (pcount,dcount,ncards) =
          (if pcount > 21
            then -1
            else if pcount > dcount then 1 else -1) + BJ (i+ncards)
        
        其中,
        得分
        将取三重(pcount、dcount、ncards)并计算结果给玩家的值

        为了实现循环终止条件(对于循环,从主
        中断
        ),只要玩家的计数大于21,我们就停止获取结果。这可以通过在映射结果之后插入
        takeWhile
        来实现…:

        options = map score $ takeWhile (\(p,_,_) -> p <= 21) $ map result [2..n-i-1]
        
        现在,您必须在这里实现动态编程/记忆

        综上所述,
        BJ
        函数有以下伪代码:

        BJ[i] = 0 if n-i < 4
        BJ[i] = maximum options
          where options = map score $ takeWhile ... $ map result [2..n-i-1]
                score (p,d,n) = (if ...p > d...) + BJ[i+n]
                result p = ...
        
        因此,代码流是:

        • 记忆版本只是索引到数组中
        • 数组是根据原始函数定义的
        • 对于任何递归调用,原始函数都会调用已记忆的函数

        以下是如何在