代码之家  ›  专栏  ›  技术社区  ›  Julian Fondren

如何循环字符串的索引?

  •  0
  • Julian Fondren  · 技术社区  · 7 年前

    考虑:

    val example = "1234567"
    
    fn digit(c: char): int =
      case- c of
      | '0' => 0 | '1' => 1 | '2' => 2 | '3' => 3 | '4' => 4
      | '5' => 5 | '6' => 6 | '7' => 7 | '8' => 8 | '9' => 9
    
    fn f(): int = loop(0, 0) where {
      fun loop(i: int, acc: int): int =
        if example[i] = '\000' then acc else
        loop(i + 1, acc + digit(example[i]))
    }
    
    implement main0() = () where {
      val () = println!("f: ", f())
    }
    

    这(尝试)循环字符串的索引,将字符串的字符相加为数字。我已经用解决了几个类似的问题 .foldleft streamize_string_char ,但实际任务需要 索引本身的数学 (即,如果i+10处的字符是偶数数字,则应仅使用字符,而不是使用每个字符)。

    实际上,数学是相关的,因为它似乎是强制的 $UNSAFE.cast2int ,因为对于的结果没有除法运算符 strlen(input) :

    fn day2(): uint = loop(input, 0, 0) where {
      val len = $UNSAFE.cast2int(strlen(input))
      fn nextindex(i: int): int = (i + len/2) mod len
      fn get(i: int): char = input[i]  // <-- also broken at this point
      // this next line is just me slowly going mad
      fun loop{n:int}{i:nat | i <= n}(s: string(n), i: size_t(i), acc: uint): uint =
        if i >= len then acc else
        if s[i] = s[nextindex(i)] then loop(i+1, acc + digit(s[i])) else
        loop(i+1, acc)
    }
    

    应该如何 f() 写在上面?请给出一个函数的示例,该函数在字符串的索引上循环,并按索引从字符串中获取字符。再说一遍,我不需要像这样的解决方案

    typedef charint = (char, int)
    fn day1(): int = sum where {
      val lastchar = input[strlen(input)-1]
      val res = input.foldleft(TYPE{charint})((lastchar, 0), (lam((last, sum): charint, c: char) =>
                    if last = c then (c, sum + digit(c)) else (c, sum)))
      val sum = res.1
    }
    

    因为我需要基于索引测试属性。

    编辑:

    我终于想到了 一些 这是一种解决方案,但看看它有多荒谬。必须有一种正确的ATS方法来实现这一点。

    #include "share/atspre_staload.hats"
    
    val example = "1234567"
    
    fn digit(c: char): int =
      case- c of
      | '0' => 0 | '1' => 1 | '2' => 2 | '3' => 3 | '4' => 4
      | '5' => 5 | '6' => 6 | '7' => 7 | '8' => 8 | '9' => 9
    
    fn f(): int = loop(0, 0) where {
      fn get(i: int): char = loop(i, string2ptr(example)) where {
        fun loop(i: int, s: ptr): char =
          if i > 0 then loop(i-1, ptr0_succ<char>(s)) else
          $UNSAFE.ptr0_get<char>(s)
      }
      fun loop(i: int, acc: int): int =
        if get(i) = '\000' then acc else
        loop(i + 1, acc + digit(get(i)))
    }
    
    implement main0() = () where {
      val () = println!("f: ", f())
    }
    

    输出:

    f: 28
    

    编辑2:

    不那么荒谬:

    ...
      val p = string2ptr(example)
      fn get(i: int): char = $UNSAFE.ptr0_get<char>(add_ptr_bsz(p, g0int2uint(i) * sizeof<char>))
    ...
    

    编辑3:

    我可以使用 string[i] 再次使用

    overload + with add_ptr_bsz
    fn string_get_at(str, i) = $UNSAFE.ptr0_get<charNZ>(string2ptr(str)+g0int2uint(i))
    overload [] with string_get_at
    

    这与我在前奏曲/日期/字符串中看到的几乎相同。日期。。。有什么问题吗?

    4 回复  |  直到 7 年前
        1
  •  1
  •   cs320 bucas    7 年前

    好的,下面的实现 day2 是安全的:

    fn
    day2
    (input: string): uint = let
    
    val
    [n:int]
    input = g1ofg0(input)
    
    val n0 = strlen(input)
    val n0 = sz2i(n0) // int(n)
    
    fun
    nextindex
    (
     i: natLt(n)
    ) : natLt(n) = nmod(i + n0/2, n0)
    
    fun
    loop(i: natLte(n), acc: uint): uint =
      if i >= n0 then acc else
      (
        if input[i] = input[nextindex(i)]
          then loop(i+1, acc + digit2uint(input[i]))
          else loop(i+1, acc)
      )
    
    in
      loop(0, 0u)
    end // end of [day2]
    
        2
  •  1
  •   cs320 bucas    7 年前

    这里有几个问题。您的功能 f() 可以写为:

    fn digit2int(c: char): int = (c - '0')
    fn f(): int = loop(example, 0, 0) where
    {
      fun
      loop
      {n:int}
      {i:nat|i <= n}
      (cs: string(n), i: int(i), acc: int): int =
      if
      string_is_atend(cs, i)
      then acc else loop(cs, i+1, acc+digit2int(cs[i]))
    }
    

    这种编程涉及依赖类型。它通常对程序员的要求更高。

        3
  •  1
  •   cs320 bucas    7 年前

    我试着重新实现你的功能 day2 :

    fn digit2int(c: char): int = (c - '0')
    
    fn
    day2(input: string): int =
      loop(0, 0) where
    {
      val n0 = strlen(input)
      val n0 =
      g0uint2int_size_int(n0)
      val p0 = string2ptr(input)
      fn nextindex(i: int): int = (i + n0/2) mod n0
      fun get(i: int): char = $UNSAFE.ptr0_get_at<char>(p0, i)
      fun loop(i: int, acc: int): int =
        if i >= n0 then acc else
        (
          if get(i) = get(nextindex(i))
            then loop(i+1, acc + digit2int(get(i))) else loop(i+1, acc)
        )
    }
    

    我不得不说,上面的实现非常丑陋(而且风格非常不安全)。如果我有时间,我将尝试稍后提供一个安全而优雅的实现。

        4
  •  0
  •   Julian Fondren    7 年前

    在提供的帮助下,我能够完成这项工作,但也有一个完整的功能示例,下面是 Day 1, 2017 Advent of Code :

    /* compile with: patscc -O2 -D_GNU_SOURCE -DATS_MEMALLOC_LIBC day1.dats -o day1 */
    #include "share/atspre_staload.hats"
    #include "share/atspre_staload_libats_ML.hats"
    
    val input: string = "12341234" /* actual value provided by contest */
    
    fn digit(c: char): uint =
      case- c of
      | '0' => 0u | '1' => 1u | '2' => 2u | '3' => 3u | '4' => 4u
      | '5' => 5u | '6' => 6u | '7' => 7u | '8' => 8u | '9' => 9u
    
    typedef charint = (char, uint)
    
    fn part1(): uint = sum where {
      val lastchar = input[strlen(input)-1]
      val res = input.foldleft(TYPE{charint})((lastchar, 0u), (lam((last, sum): charint, c: char) =>
                    if last = c then (c, sum + digit(c)) else (c, sum)))
      val sum = res.1
    }
    
    typedef natLT(n:int) = [i:nat | i < n] int(i)
    typedef natLTe(n:int) = [i:nat | i <= n] int(i)
    
    fn part2(): uint = loop(0, 0u) where {
      val [n:int] input = g1ofg0(input)
      val len = sz2i(strlen(input))
      fn nextindex(i: natLT(n)): natLT(n) = nmod(i + len/2, len)
      fun loop(i: natLTe(n), acc: uint): uint =
        if i >= len then acc else
        if input[i] = input[nextindex(i)] then loop(i+1, acc + digit(input[i])) else
        loop(i+1, acc)
    }
    
    extern fun reset_timer(): void = "ext#reset_timer"
    extern fun elapsed_time(): double = "ext#elapsed_time"
    %{
    #include <sys/time.h>
    #include <time.h>
    struct timeval timer_timeval;
    void reset_timer() { gettimeofday(&timer_timeval, NULL); }
    double elapsed_time() {
      struct timeval now;
      gettimeofday(&now, NULL);
      int secs = now.tv_sec - timer_timeval.tv_sec;
      double ms = (now.tv_usec - timer_timeval.tv_usec) / ((double)1000000);
      return(secs + ms);
    }
    %}
    
    fn bench(f: () -> void) = () where {
      val () = reset_timer()
      val () = f()
      val c = elapsed_time()
      val () = println!(" (timing: ", c, ")")
    }
    
    implement main0() =
      begin
        bench(lam() => print!("part1: ", part1()));
        bench(lam() => print!("part2: ", part2()));
      end
    

    输出(对于假“12341234”输入):

    part1: 0 (timing: 0.000137)
    part2: 20 (timing: 0.000001)