如何使用' getChar'来递归填充具有从属对的Idris字符结构?

时间:2016-05-22 08:36:04

标签: recursion idris

任何人都可以帮我这个..

这是我追求的数据结构:

example : (n : Nat ** Vect n (n1 : Nat ** Vect n1 Char))
example = (3 ** [(3 ** ['a', 'b', 'c']), (3 ** ['d', 'e', 'f']), (3 ** ['g', 'h', 'i'])])

我想读取STDIN中的字符,并为每个\ n创建一个带有该行字符的新向量。空行结束递归。

这将是上述示例的输入:

abc\n
def\n
ghi\n
\n

我想知道一个递归函数是否可行。像这样对整个字符串:

read_vect : IO (len ** Vect len String)
read_vect = do x <- getLine
               if (x == "")
                  then pure (_ ** [])
                  else do (_ ** xs) <- read_vect
                          pure (_ ** x :: xs)

非常感谢提前! 杰森。

2 个答案:

答案 0 :(得分:1)

编辑,getLine:不想要一个实际的矩阵,这很简单:

read_structure : IO (k : Nat ** Vect k (l : Nat ** Vect l Char))
read_structure = do str <- getLine
                    let chrs = unpack str
                    let x = fromList chrs
                    if length chrs == 0
                       then pure (_ ** [])
                       else do (_ ** xs) <- read_structure
                               pure (_ ** (_ ** x) :: xs)

Idris可以推断出最多的东西(**::更强大,但为了说清楚,详细版本将是:

                       then pure (0 ** [])
                       else do (n ** xs) <- read_structure
                               pure ((S n) ** ((length chrs ** x) :: xs))

修改,getChar:如果您确实希望使用getChar进行递归,则以下版本在使用read_list True打包时会获得{{1} }}。如果连续存在两个List (List Char)break参数就会找出。

'\n'

要使用read_list : Bool -> IO (List (List Char)) read_list break = do chr <- getChar if chr == '\n' then if break then pure [] else do rest <- read_list True pure ([] :: rest) else do rest <- read_list False case rest of x :: xs => pure ((chr :: x) :: xs) Nil => pure ([chr] :: Nil) 来完成这项工作,您只需要输入一些k : Nat ** Vect k (l : Nat ** Vect l Char)

(_ ** xs)

read_vects : Bool -> IO (k : Nat ** Vect k (l : Nat ** Vect l Char)) read_vects break = do chr <- getChar if chr == '\n' then if break then pure (_ ** []) else do (_ ** rest) <- read_vects True pure (_ ** (_ ** []) :: rest) else do (_ ** rest) <- read_vects False case rest of (_ ** x) :: xs => pure (_ ** (_ ** (chr :: x)) :: xs) Nil => pure (_ ** (_ ** [chr]) :: Nil) 版本肯定更具可读性,正如Cactus所指出的,List几乎等同于List a。因此,您可以先解析它,然后转换为k ** Vect k a s。

答案 1 :(得分:0)

example中的类型与List (List Char)同构,因为你可以做到

listToVect : List a -> (n : Nat ** Vect n a)
listToVect xs = (length xs ** fromList xs)

vectToList : (n : Nat ** Vect n a) -> List a
vectToList (_ ** xs) = toList xs

所以我们可以用List

来写
lines : List Char -> List (List Char)
lines = foldr step []
  where
    step : Char -> List (List Char) -> List (List Char)
    step '\n' ls = [] :: ls
    step c [] = [[c]]
    step c (l::ls) = (c::l) :: ls

lines' : String -> (n : Nat ** Vect n (n' : Nat ** Vect n' Char))
lines' = listToVect . map listToVect . lines . unpack

但是,我不相信这是你想要的。

对于某些固定的List (List Char)Vect n (Vect m Char),字符矩阵不是n,而是m,因为它的整个点是矩阵是所有行都是相同的长度。

我们可以将其实现为

Matrix : Nat -> Nat -> Type -> Type
Matrix n m a = Vect n (Vect m a)

然后写一些解析给定大小的矩阵:

parseLine : (m : Nat) -> List Char -> Maybe (Vect m Char, List Char)
parseLine Z ('\n'::cs) = Just ([], cs)
parseLine (S m) (c :: cs) = map (\(l, cs') => (c::l, cs')) $ parseLine m cs
parseLine _ _ = Nothing

parseMatrix' : (n : Nat) -> (m : Nat) -> List Char -> Maybe (Matrix n m Char, List Char)
parseMatrix' Z m ['\n'] = Just ([], [])
parseMatrix' (S n) m cs = case parseLine m cs of
  Nothing => Nothing
  Just (l, cs') => case parseMatrix' n m cs' of
    Nothing => Nothing
    Just (ls, cs'') => Just (l::ls, cs'')
parseMatrix' _ _ _ = Nothing

parseMatrix : (n : Nat) -> (m : Nat) -> String -> Maybe (Matrix n m Char)
parseMatrix n m = map fst . parseMatrix' n m . unpack

这仍然不是你想要的,因为预先nm而不是查看输入;所以也许我们应该选择

SomeMatrix : Type -> Type
SomeMatrix a = (n ** (m ** Matrix n m a))

导致

parseSomeMatrix : String -> Maybe (SomeMatrix Char)
parseSomeMatrix cs = case map unpack (lines cs) of
    l::ls => parseFrom l ls
    [] => Just (0 ** (0 ** []))
  where
    parseFrom : List Char -> List (List Char) -> Maybe (SomeMatrix Char)
    parseFrom cs ls = map (\vs => (length vs ** (m ** fromList vs))) (parseInto ls)
      where
        m : Nat
        m = length cs

        parseInto : List (List Char) -> Maybe (List (Vect m Char))
        parseInto [] = Just []
        parseInto (l :: ls) with (decEq (length l) m)
          | Yes p = map (\vs => (replace {P = \m => Vect m Char} p (fromList l)) :: vs) (parseInto ls)
          | No _ = Nothing