Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.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
Algorithm 如何将非线性列表迭代方案抽象为可重用的算法?_Algorithm_F#_Dsl - Fatal编程技术网

Algorithm 如何将非线性列表迭代方案抽象为可重用的算法?

Algorithm 如何将非线性列表迭代方案抽象为可重用的算法?,algorithm,f#,dsl,Algorithm,F#,Dsl,有一个奇怪的机会,某人有一个绝妙的主意 我不确定是否有一个好的方法来概括这一点 编辑:我认为准确地解释输入和输出是什么可能会很好。下面的代码只是我处理解决方案的方式 输入:数据、配方 数据:字符串集,这里的字符串列表也称为“命名列表集” 配方:命令列表 命令打印(文字列表参考) 将文本添加到输出中,或者如果它是列表引用,则将引用列表的头添加到输出中 命令While(列表参考) 被引用时列表不为空-->下一个命令 被引用时,列表为空-->跳过配方列表中超过匹配Wend的条目 命令Wend(列表参考

有一个奇怪的机会,某人有一个绝妙的主意

我不确定是否有一个好的方法来概括这一点

编辑:我认为准确地解释输入和输出是什么可能会很好。下面的代码只是我处理解决方案的方式

输入:数据、配方

数据:字符串集,这里的字符串列表也称为“命名列表集”
配方:命令列表

命令打印(文字列表参考)
将文本添加到输出中,或者如果它是列表引用,则将引用列表的头添加到输出中

命令While(列表参考)
被引用时列表不为空-->下一个命令
被引用时,列表为空-->跳过配方列表中超过匹配Wend的条目

命令Wend(列表参考)
将引用列表替换为尾部(引用列表) 当引用列表为空时,下一个命令 当引用列表不为空时,下一个命令是上面的匹配命令

输出:字符串列表

最好的答案是实现最短的算法,并允许在新的上下文中重复使用该算法

顺便说一句,这不仅仅是一个有趣的编程问题。如果您尝试实现数据驱动的文本模板,基本上会发生这种情况

下面的代码是我试图解决这个问题的代码。 第一个代码段是一个非通用的解决方案。 第二个代码段是尝试隔离算法。 如果您使用代码,只需将第二个代码段粘贴到第一个代码段下面,两个版本都可以使用

整个主题是关于更好地理解如何将迭代算法与代码的其余部分分离,然后简单地应用它,而不是将所有其他代码都包含在其中

如果有一种方法可以抽象语句的处理方式和while/wend的循环,这不是很好吗, 它可以在我的主代码中重用,就像我不断重复使用其他“迭代方案”,比如List.map

我的主要代码与本研究的共同点是:

  • 一个不断发展的“环境”,贯穿计算的所有步骤
  • 集合,需要以格式良好的嵌套方式进行迭代。(格式错误为:while x while y wend x wend y)
  • 一系列“执行步骤”构成了每个“while-wend”循环的主体
  • 以“纯粹”的方式完成。正如你会注意到的,研究中没有什么是可变的。我想保持这样
  • 每个“While”都引入了一个新的作用域(如绑定值),一旦While循环完成,就会再次丢弃该作用域
  • 因此,我正在寻找类似于:

    运行:CommandClassifier->commandExecutor->Command list->EnvType->EnvType

    在哪里

    CommandClassifier可以是form Command->NORMAL | LOOP_START | LOOP_END的函数

    和commandexecutor:Command->EnvType->EnvType

    当然,这些while块的嵌套将不限于2(只是试图保持testProgram()较小)

    旁注:“命令列表”是来自前面解析器运行的AST,但这并不重要

    type MiniLanguage =
        | Print of string
        | While of string
        | Wend of string
    
    let testProgram = 
        [   Print("Hello, I am your Mini Language program")
            While("names")
            Print("<names>")
            While("pets")
            Print("<pets>")
            Wend("pets")
            Print("Done with pets.")
            Wend("names")
            Print("Done with names.")
        ]
    
    type MiniEnvironment = { Bindings : Map<string,string>; Collections : Map<string, string list> }
    
    let init collections =
        { Bindings = Map.empty; Collections = Map.ofList collections}
    
    let bind n v env =
        let newBindings =
            env.Bindings
            |> Map.remove n
            |> Map.add n v
        { env with Bindings = newBindings; }
    
    let unbind n env =
        { env with Bindings = Map.remove n env.Bindings; }
    
    let bindingValue n env =
        if env.Bindings.ContainsKey n then
            Some(env.Bindings.Item n)
        else 
            None
    
    let consumeFirstFromCollection n env =
        if env.Collections.ContainsKey n then
            let coll = env.Collections.Item n
            match coll with
            | [] -> env |> unbind n
            | _ ->
                let first = coll.Head
                let newCollections = 
                    env.Collections
                    |> Map.remove n
                    |> Map.add n coll.Tail
                { env with Collections = newCollections } 
                |> bind n first
        else failwith ("Unknown collection: " + n)
    
    // All do functions take env - the execution environment - as last argument.
    // All do functions return (a new) env as single return parameter.
    let rec doPrint (s : string) env = 
        if s.StartsWith("<") && s.EndsWith(">") then
            match bindingValue (s.Substring (1, s.Length - 2 )) env with
            | Some(v) -> v
            | _ -> s
        else s 
        |> printfn "%s"
        env
    
    let rec skipPastWend name code =
        match code with
        | (Wend(cl) :: rest) when cl = name -> rest
        | [] -> failwith "No Wend found!"
        | (_ :: rest) -> skipPastWend name rest
    
    let rec doWhileX name code env =
        match code with
        | (Print(s) :: rest) -> env |> (doPrint s) |> doWhileX name rest
        | (While(cn) :: rest) -> env |> doWhile cn rest |> ignore; env |> doWhileX name (skipPastWend cn rest)
        | (Wend(cn) :: rest) when cn = name -> env
        | [] -> failwith ("While without Wend for: " + name)
        | _ -> failwith ("nested while refering to same collection!")
    
    and doWhile name code env =
        let e0 = env |> consumeFirstFromCollection name
        match bindingValue name e0 with
        | Some(s) ->
            e0 |> doWhileX name code |> doWhile name code
        | None -> env
    
    let rec run (program : MiniLanguage list) env =
        match program with
        | (Print(s) :: rest) -> env |> (doPrint s) |> run rest
        | (While(cn) :: rest) -> 
            env 
            |> doWhile cn rest |> ignore
            env |> run (skipPastWend cn program)
        | (Wend(cn) :: rest) -> failwith "wend found in run()"
        | [] -> env
    
    let test() =
        init [ "names", ["name1"; "name2"; "name3"; ]; "pets", ["pet1"; "pet2"] ] 
        |> run testProgram
        |> printfn "%A"
    
    (*
    Running test() yields:
    
    Hello, I am your Mini Language program
    name1
    pet1
    pet2
    Done with pets.
    name2
    pet1
    pet2
    Done with pets.
    name3
    pet1
    pet2
    Done with pets.
    Done with names.
    {Bindings = map [];
     Collections =
      map [("names", ["name1"; "name2"; "name3"]); ("pets", ["pet1"; "pet2"])];}
    
    
    *)
    
    类型小型语言=
    |字符串打印
    |弦乐
    |线纹
    让testProgram=
    [打印(“你好,我是你的迷你语言程序”)
    而(“姓名”)
    打印(“”)
    While(“宠物”)
    打印(“”)
    温德(“宠物”)
    打印(“与宠物一起完成”)
    温德(“姓名”)
    打印(“使用名称完成”)
    ]
    类型MiniEnvironment={Bindings:Map;Collections:Map}
    让我们初始化集合=
    {Bindings=Map.empty;Collections=Map.ofList Collections}
    让我们绑定n v env=
    让新发现=
    环境绑定
    |>删除
    |>添加
    {env with Bindings=newBindings;}
    让我们解开纽扣=
    {env with Bindings=Map.remove n env.Bindings;}
    让bindingValue n env=
    如果env.Bindings.ContainsKey n,则
    一些(env.Bindings.Item n)
    其他的
    没有一个
    让consumerfirstfromcollection n env=
    如果env.Collections.ContainsKey n,则
    设coll=env.Collections.Item n
    搭配
    |[]->env |>unbind n
    | _ ->
    let first=coll.Head
    让新集合=
    环境收藏
    |>删除
    |>映射添加n coll.Tail
    {env with Collections=newCollections}
    |>先绑定n
    else failwith(“未知集合:+n”)
    //所有do函数都将env(执行环境)作为最后一个参数。
    //所有do函数都以单个返回参数的形式返回(一个新的)env。
    让rec doPrint(s:string)env=
    如果s.StartsWith(“”),则
    将bindingValue(s.Substring(1,s.Length-2))env与
    |一些(v)->v
    |_uuS->s
    其他
    |>打印fn“%s”
    环境
    让记录跳过名称代码=
    匹配代码
    |当cl=name->rest时(Wend(cl)::rest
    |[]->失败,并显示“未找到Wend!”
    |(\:rest)->skipPastWend name rest
    让rec doWhileX名称代码env=
    匹配代码
    |(打印):rest)->env |>(doPrint s)|>doWhileX name rest
    |(While(cn)::rest->env |>doWhile cn rest |>ignore;环境|>doWhileX名称(skipPastWend cn rest)
    |当cn=name->env时(Wend(cn)::rest
    |[]->failwith(“而不使用Wend for:”+名称)
    |->failwith(“引用同一集合时嵌套!”)
    和doWhile名称代码env=
    设e0=env |>consumeFirstFromCollection名称
    将bindingValue名称e0与匹配
    |部分-->
    e0 |>doWhileX名称代码|>doWhile名称代码
    |无->环境
    让rec运行(程序:小型语言列表)env=
    将程序与
    |(打印):rest->env |>(doPrint s)|>运行rest
    |(While(cn)::rest->
    环境
    |>doWhile cn rest |>忽略
    环境|>run(skipPastWe
    
    // The only function I had to "modify" to work with new "generalized" algorithm.
    let consumeFirstFromCollection1 n env =
        if env.Collections.ContainsKey n then
            let coll = env.Collections.Item n
            match coll with
            | [] -> (env |> unbind n , false)
            | _ ->
                let first = coll.Head
                let newCollections = 
                    env.Collections
                    |> Map.remove n
                    |> Map.add n coll.Tail
                ({ env with Collections = newCollections } 
                    |> bind n first , true)
        else failwith ("Unknown collection: " + n)
    
    type NamedList<'n,'t when 'n : comparison> = 'n * List<'t>
    type Action<'a,'c> = 'c -> 'a -> 'a
    type LoopPreparer<'a,'c> = 'c -> 'a -> 'a * bool
    type CommandType = | RUN | BEGIN | END
    type CommandClassifier<'c> = 'c -> CommandType
    type Skipper<'c> = 'c -> List<'c> -> List<'c>
    
    type InterpreterContext<'a,'c> =
        { classifier : CommandClassifier<'c>
          executor : Action<'a,'c>
          skipper : Skipper<'c>
          prepareLoop : LoopPreparer<'a,'c>
          isMatchingEnd : 'c -> 'c -> bool
        }
    
    let interpret (context : InterpreterContext<'a,'c>) (program : 'c list) (env : 'a) : 'a =
        let rec loop front (code : 'c list) e =
            let e0,hasData = e |> context.prepareLoop front
            if hasData 
            then 
                e0 
                |> loop1 front (code) 
                |> loop front (code) 
            else e
    
        and loop1 front code e =
            match code with
            | x :: more when (context.classifier x) = RUN -> 
                //printfn "RUN %A" x
                e |> context.executor x |> loop1 front more
            | x :: more when (context.classifier x) = BEGIN -> 
                //printfn "BEGIN %A" x
                e |> loop x more |> ignore
                e |> loop1 front (context.skipper x more)
            | x :: more when (((context.classifier x) = END) && (context.isMatchingEnd front x)) ->   ///  && (context.isMatchingEnd front x)
                //printfn "END %A" x
                e
            | [] -> failwith "No END."
            | _ -> failwith "TODO: Not sure which case this is. But it is not a legal one!"
    
        let rec interpr code e =
            match code with
            | [] -> e
            | (first :: rest) -> 
                match context.classifier first with
                | RUN -> env |> context.executor first |> interpr rest
                | BEGIN -> 
                    e |> loop first rest |> ignore
                    e |> interpr (context.skipper first rest)
                | END -> failwith "END without BEGIN."
        interpr program env
    
    
    
    let test1() =
        let context : InterpreterContext<MiniEnvironment,MiniLanguage> = 
            {   classifier = fun c-> match c with | MiniLanguage.Print(_) -> RUN | MiniLanguage.While(_) -> BEGIN | MiniLanguage.Wend(_) -> END;
                executor = fun c env -> match c with | Print(s) -> doPrint s env | _ -> failwith "Not a known command.";
                skipper = fun c cl -> match c with | While(n) -> skipPastWend n cl | _ -> failwith "first arg of skipper SHALL be While!"
                prepareLoop = fun c env -> match c with | While(n) -> (consumeFirstFromCollection1 n env) | _ -> failwith "first arg of skipper SHALL be While!"
                isMatchingEnd = fun cwhile cx -> match cwhile,cx with | (While(n),Wend(p)) when n = p -> true | _ -> false
            }
        init [ "names", ["name1"; "name2"; "name3"; ]; "pets", ["pet1"; "pet2"] ]
        |> interpret context testProgram
        |> printfn "%A"