【问题标题】:Create a function with for loop syntax使用 for 循环语法创建函数
【发布时间】:2013-05-01 14:59:18
【问题描述】:

是否可以使用“for 循环”样式语法创建函数?如果是这样,那这种风格的函数会被称为什么?

例如,for 循环遵循以下语法:

for(i = 0; i < 10; i++)
{
    //do something
}

是否可以用任何语言创建自己的函数,例如,称为“myFunction”的函数可以这样调用:

myFunction(x; y; z)
{
   //do something
}

(注意函数输入的分号而不是逗号,然后是块包装器)

通常在编程语言中,您只能创建一个函数并像这样调用它:

myFunction(input1, input2, input2);

所以基本上我希望能够创建一个接受输入的函数,用分号和代码块分隔,就像 for 循环一样。这可能吗?这叫什么?

编辑 - 澄清:我不想编写一个运行循环的快捷函数。我正在寻找编写一个组合函数,从语法的角度来看,它看起来像一个 for 循环。但是,组合函数永远不会调用“for”或出于任何原因。

编辑 - 这可以在“编译器”级别实现吗?我了解 JavaScript 中最接近的内容如下(但它不像 for 那样干净):

myFunction(x, y, z, function()
{
    //do something
});

【问题讨论】:

  • “不,你不能那样做”...
  • 您标记了两种不同的编程语言。你问的是哪一个?
  • 如果您能解释为什么要这样做,那么人们可能会有一些替代建议。
  • 虽然你不能这样做,但你可以使用 [].map 在私有范围内进行迭代。
  • @squint 两种语言

标签: javascript coding-style


【解决方案1】:

嗯...正如您已经说过的:您可以创建自己的方法,但不能创建关键字。 for 就是这样一个关键字,关键字不必遵守常规规则,方法可以这样做。

我能想到的最接近的事情是这样的:

void MyForLoop<T>(Func<T> myInitialization, Func<T, bool> myCondition, Func<T, T> myIteration, Action<T> myBody)
{
   // Check the arguments for null's.
    T iterator = myInitialization();
    while(myCondition(iterator))
    {
         myBody(value);
         value = myIteration(value);
    }
}

你可以这样称呼它:

MyForLoop(() => 0, i => i < 10, i => i + 1, i => Console.WriteLine(i));

【讨论】:

  • 是否可以编写一个接受块的函数,如 using(var thing=value){//block} 或 switch(varname){//block}
  • 有点...我建议您再次发布该问题,以便我们可以与此问题分开回答。
【解决方案2】:

您正在寻找一种新的 DSL(领域特定语言)。 Java、python、javascript 和其他语言确实在不同程度上对此提供了支持。 DSL 有时可能涉及特殊语法,例如您希望对分号执行的操作,或者它可以像编写非常好的 API 的能力一样简单(想想 jQuery)。 JavaScript 不支持自定义语法,但该语言非常具有表现力,并且很容易创建一个读起来像英语的 api。

话虽如此,您可以继续按照您想要的方式编写代码,然后通过某种解析器运行它并进行转换。你应该看看coffeescript的源代码。您基本上需要熟悉编写自己的语言、创建语法、将内容解析为语法树和翻译代码。

就像我说的,其他语言确实支持创建自己的语法/DSL。以下是一些资源:
- http://www.slideshare.net/Siddhi/creating-domain-specific-languages-in-python
- http://www.jetbrains.com/mps/

就我个人而言,我认为任何时候您自定义的语法都会让从事该项目的新人感到非常困惑。但是,也许这对您正在做的事情有意义。

【讨论】:

    【解决方案3】:

    您的确切语法在 JavaScript 中是不可能的,但您想要的意图是。您想要的与现代浏览器中Array 上提供的forEach 非常相似。

    function myLooper(iterations, callback) {
        for(var i = 0; i < iterations; ++i) {
            callback(i);
        }
    }
    
    myLooper(4, function(i) {
        console.log(i);
    });
    
    // outputs
    // 0
    // 1
    // 2
    // 3
    

    这里有一个fiddle 用于上述内容。

    因为你也用 C# 标记了它,这里有一个 C# 版本:

    void MyLooper(int iterations, Action<int> action) {
        for(int i = 0; i < iterations; ++i) {
            action.Invoke(i);
        }
     }
    

    我现在手头没有 C# 环境,所以上面可能不太正确。

    【讨论】:

      【解决方案4】:

      您要求 c# 中的解决方案,如果 f# 中的某些内容(afaik 这些语言可以“一起”使用)也受到赞赏,那么我可以为您提供以下 sn-ps(请注意,分隔不是用分号如你所愿,但有空格):

      函数 yourLoop 接受三个参数,两个整数:lowerBound upperBound 和一个函数(具有更具体的 'a -> unit 类型的副作用):body 意思是

      yourLoop (lowerBound:int) upperBound body
      

      效果和

      一样
      for i in lowerBound..upperBound do
        body(i)
      

      函数如下:

      let rec yourLoop (lowerBound:int) upperBound body =
        if (lowerBound >= upperBound) then body upperBound
        else
          body lowerBound
          yourLoop (lowerBound+1) upperBound body 
      

      例如,让它成为某个方法的主体

      let something i = printfn "%s%i" "do something with " i
      

      然后申请

      yourLoop 0 5 something
      

      产量

      do something with 0
      do something with 1
      do something with 2
      do something with 3
      do something with 4
      do something with 5
      

      同样,如果你想自顶向下循环,那么你可以写

      let rec yourInvertedLoop lowerBound upperBound body =
        if (lowerBound >= upperBound) then body lowerBound
        else
          body upperBound
          yourInvertedLoop (lowerBound) (upperBound-1) body
      

      屈服

      yourInvertedLoop 0 5 something
      
      do something with 5
      do something with 4
      do something with 3
      do something with 2
      do something with 1
      do something with 0
      

      对于更通用的功能,请考虑

      let rec yourLoopIncr lowerBound upperBound next body =
        if (next lowerBound >= upperBound) then body lowerBound
        else
          body lowerBound
          yourLoopIncr (next lowerBound) upperBound next body 
      

      您可以在其中指定循环的迭代方式。例如,

      yourLoopIncr 1 25 (fun x-> 2*x) something
      

      会产生

      do something with 1
      do something with 2
      do something with 4
      do something with 8
      do something with 16
      

      备注:请注意,此解决方案仅适用于不返回值的主体。当然,您仍然可以在控制台上写东西或改变变量等。例如将代码

      let mutable x = 0
      let somethingElse n = x <- x+n 
      yourLoop 0 10 somethingElse
      

      将 x 设置为 55。

      【讨论】:

        【解决方案5】:

        您希望函数接受以分号分隔的输入,为什么不将您的输入连接成一个以分号分隔的字符串!如果这对您有意义,那么只需将所有输入放在一个数组中并在数组上执行 .join(';')。或者只是传递数组本身,如果分号不是您的特定要求。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-08
          • 2022-01-13
          • 2022-01-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-27
          • 1970-01-01
          相关资源
          最近更新 更多