Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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 - Fatal编程技术网

Haskell “哈斯克尔”;“弦乐运动”;功能

Haskell “哈斯克尔”;“弦乐运动”;功能,haskell,Haskell,我正在尝试使用Haskell、hscurses和Data.text构建一个简单的文本编辑器。我对哈斯克尔是个新手 以下是我的代码片段: data Cursor = Cursor { position :: Int, line :: Int, column :: Int } deriving (Eq, Show) isNewline :: Char -> Bool isNewline c = c == '\n' onNewline :: T.Text ->

我正在尝试使用Haskell、hscurses和Data.text构建一个简单的文本编辑器。我对哈斯克尔是个新手

以下是我的代码片段:

data Cursor = Cursor {
  position :: Int,
  line     :: Int,
  column   :: Int
} deriving (Eq, Show)

isNewline :: Char -> Bool
isNewline c = c == '\n'

onNewline :: T.Text -> Int -> Bool
onNewline buf pos
  | pos >= T.length buf = False
  | otherwise           = isNewline $ T.index buf pos

findIndex :: (Char -> Bool) -> T.Text -> Int -> Maybe Int
findIndex pred buf pos
  | buf == T.empty = Just 0
  | otherwise      = rightWhile pos
  where rightWhile pos
          | pos > bufMax buf       = Nothing
          | pred $ T.index buf pos = Just pos
          | otherwise              = rightWhile (pos + 1)

findIndexLeft :: (Char -> Bool) -> T.Text -> Int -> Maybe Int
findIndexLeft pred buf pos = leftWhile pos
  where leftWhile pos
          | pos < 0                = Nothing
          | pred $ T.index buf pos = Just pos
          | otherwise              = leftWhile (pos - 1)

startOfLine :: T.Text -> Int -> Int
startOfLine buf pos = case findIndexLeft isNewline buf (pos - 1) of
  Nothing -> 0
  Just p  -> p + 1

endOfLine :: T.Text -> Int -> Int
endOfLine buf pos = case findIndex isNewline buf pos of
  Nothing -> 1 + bufMax buf
  Just p  -> p

lineOffset :: T.Text -> Int -> Int
lineOffset buf pos = pos - startOfLine buf pos

lineLength :: T.Text -> Int -> Int
lineLength buf pos = endOfLine buf pos - startOfLine buf pos

bufMax :: T.Text -> Int
bufMax buf = max 0 $ T.length buf - 1

bufLines :: T.Text -> Int
bufLines = T.foldl (\acc c -> if isNewline c then (acc+1) else acc) 0

moveCursorRight :: T.Text -> Cursor -> Cursor
moveCursorRight buf c@(Cursor pos line col)
  | buf == T.empty = c
  | otherwise      = Cursor newPos newLine newCol
  where end       = 1 + bufMax buf
        onEnd     = pos == end
        newPos    = clip (pos + 1) 0 end
        newLine   = if onNewline buf pos && not onEnd
                    then line + 1
                    else line
        newCol    = lineOffset buf newPos

moveCursorLeft :: T.Text -> Cursor -> Cursor
moveCursorLeft buf (Cursor pos line col) =
  Cursor newPos newLine newCol
  where onStart   = pos == 0
        newPos    = clipLow (pos - 1) 0
        newLine   = if onNewline buf newPos && not onStart
                    then line - 1
                    else line
        newCol    = lineOffset buf newPos

-- More movement functions follow...
但这并没有太大帮助,因为“at”必须与“before”连用,而且根据文档,
t.cons
是O(n)。。。此外,当实际显示完成时,以线为中心的方法更好


感谢所有帮助过我的人

正如gallais在评论中所说,你想使用拉链。其思想是,您的“游标”实际上是一个如下所示的数据结构:

type Line = T.Text

data TextZipper = TextZipper {
   textBefore :: [Line],
   currentLine :: Line,
   textAfter :: [Line]
}
moveDown :: TextZipper -> Maybe TextZipper
moveDown tzip = case textAfter tzip of
   [] -> Nothing    -- Already at the bottom of the file.
   t:ts -> TextZipper {
      textBefore = currentLine tzip : textBefore tzip,
      currentLine = t,
      textAfter = ts
   }
诀窍是“textbevere”以相反的顺序包含光标上方的行。因此,要向下移动一行,请将“currentLine”放在“textBefore”的开头,并从“textAfter”中取出新的“currentLine”,如下所示:

type Line = T.Text

data TextZipper = TextZipper {
   textBefore :: [Line],
   currentLine :: Line,
   textAfter :: [Line]
}
moveDown :: TextZipper -> Maybe TextZipper
moveDown tzip = case textAfter tzip of
   [] -> Nothing    -- Already at the bottom of the file.
   t:ts -> TextZipper {
      textBefore = currentLine tzip : textBefore tzip,
      currentLine = t,
      textAfter = ts
   }
moveUp将非常类似。您还需要一个textZipperToList函数来提取拉链的内容以进行保存,还需要一个textZipperFromList函数


我记得在某个地方读到,Emacs使用了一个类似的概念,只是它是通过字符而不是行来实现的。缓冲区表示为两个文本块,一个在光标前,一个在光标后。移动光标是通过将字符从一个块复制到另一个块来完成的。这里也有同样的概念。考虑到这一点,您可能需要考虑将每个行列表替换为单个文本值。

您可能需要将缓冲区表示为行列表,使用表示当前位置的。对于Agda中的一个指导性示例(您可以在Haskell中复制相当多的工作),您可以查看另一个请参见:。有一种方法可以将
findIndex
加速到O(n),但之后您仍然使用索引位置,因此从长远来看,这对您没有帮助。如果您需要跳转,您应该使用
Data.sequence
从列表拉链切换到序列拉链<代码>数据拉链a=拉链(序列a)a(序列a)或类似产品。不像列表拉链,你可以保持一切有序,因为结束和开始一样快。您可以在
O(logn)
时间中移动
n
步骤。