3

我正在用 Haskell 编写数独生成器/求解器作为学习练习。

我的solve函数接受 aUArray但返回 aState Int (UArray ...)以便它还可以返回它在解决时找到的最大难度级别。

到目前为止,这是我的功能(仍处于非常实验性的早期阶段):

import Control.Monad.State       (State, put)
import Control.Monad.Trans.Class (lift)
import Data.Array.MArray         (thaw)
import Data.Array.ST             (runSTUArray)
import Data.Array.Unboxed        (UArray)

-- ...

type Cell = Word16

solve :: UArray (Int, Int) Cell -> State Int (UArray (Int, Int) Cell)
solve grid = do
  return $ runSTUArray $ do
    arr <- thaw grid
    lift $ put 42
    return arr

它还没有真正对可变数组做任何事情。我只是想让它使用 进行类型检查put 42,但目前收到以下错误:

  • Couldn't match kind ‘*’ with ‘* -> *’
    When matching the kind of ‘ST’
  • In a stmt of a 'do' block: lift $ put 42
    In the second argument of ‘($)’, namely
      ‘do arr <- thaw grid
          lift $ put 42
          return arr’
    In the second argument of ‘($)’, namely
      ‘runSTUArray
         $ do arr <- thaw grid
              lift $ put 42
              return arr’
     |
 128 |     lift $ put 42
     |     ^^^^^^^^^^^^^
4

3 回答 3

1

runSTUArray ...是一个纯值,它对“外部单子”一无所知。并且State关心你如何使用它,你不能将它不透明地传递给 ST。

你可以做什么:

选项1:更改整个程序以将更多逻辑移至ST端。然后,您将使用 STRef 而不是 State:

solve :: ST s (STRef Int) -> ST s (UArray (Int, Int) Cell) -> ST s ()
...

选项2:手动提取并传递给ST,然后返回并显式放置。但是有并发症。runSTUArray不允许与数组一起获取另一个值。我不知道如何使用当前的数组函数安全地完成它。不安全的是,您可以更好地重新实现runSTUArray它可以传递另一个值。您还可以添加假单元格并在那里对新状态进行编码。

导出另一个值的方法存在于向量包中,有(在新版本中)createT函数可以不采用裸向量,而是包含它的结构(甚至是多个向量)。因此,总的来说,您的示例如下:

import Control.Monad.State (State, put, get)
import Data.Word (Word16)

import qualified Data.Vector.Unboxed as DVU

type Cell = Word16

solve :: DVU.Vector Cell -> State Int (DVU.Vector Cell)
solve grid = do
  oldState <- get
  let (newState, newGrid) = DVU.createT (do
          arr <- DVU.thaw grid
          pure (oldState + 42, arr))
  put newState
  pure newGrid

不幸的是,向量只是一维的

于 2018-03-19T04:00:54.773 回答
0

solve grid有形式return $ ...。这意味着它State Int (UArray (Int, Int) Cell)只是专门Monad m => m (UArray (Int, Int) Cell)的 -...无法访问此特定 monad 的功能,它只是UArray (Int, Int) Cell您返回的一个值。

于 2018-03-18T17:04:41.763 回答
0

State在将monad更改为 tuple 后,我能够获得一些细微的变化来编译和运行(Int, Grid)

import Control.Monad.ST    (ST, runST)
import Data.Array.MArray   (freeze, thaw, writeArray)
import Data.Array.ST       (STUArray)
import Data.Array.Unboxed  (UArray)
import Data.Word (Word16)

type Cell = Word16
type Grid = UArray (Int, Int) Cell

solve :: Grid -> (Int, Grid)
solve grid =
  runST $ do
    mut <- thaw grid :: ST s (STUArray s (Int, Int) Cell)
    writeArray mut (0, 0) 0 -- test that I can actually write
    frozen <- freeze mut
    return (42, frozen)

这适用于我的应用程序。

于 2018-06-01T13:33:28.117 回答