Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/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
Haskell 您是否发现仍然需要可以更改的变量,如果需要,原因是什么?_Haskell_Variables_Functional Programming_Ssa_Modern Languages - Fatal编程技术网

Haskell 您是否发现仍然需要可以更改的变量,如果需要,原因是什么?

Haskell 您是否发现仍然需要可以更改的变量,如果需要,原因是什么?,haskell,variables,functional-programming,ssa,modern-languages,Haskell,Variables,Functional Programming,Ssa,Modern Languages,我听到的反对函数式语言的一个论点是,单赋值编码太难了,或者至少比“普通”编程要困难得多 但是通过查看我的代码,我意识到我真的没有太多(任何?)的使用模式,如果你用一种相当现代的语言编写的话,就不能像使用单一赋值形式那样编写 那么,在一次范围调用中变化的变量的用例是什么呢?请记住,在这种情况下,循环索引、参数和其他在调用之间变化的范围绑定值不是多个赋值(除非您出于某种原因必须在主体中更改它们),并假设您正在使用远高于汇编语言级别的语言编写,在这里您可以编写以下内容 values.sum 或(如果

我听到的反对函数式语言的一个论点是,单赋值编码太难了,或者至少比“普通”编程要困难得多

但是通过查看我的代码,我意识到我真的没有太多(任何?)的使用模式,如果你用一种相当现代的语言编写的话,就不能像使用单一赋值形式那样编写

那么,在一次范围调用中变化的变量的用例是什么呢?请记住,在这种情况下,循环索引、参数和其他在调用之间变化的范围绑定值不是多个赋值(除非您出于某种原因必须在主体中更改它们),并假设您正在使用远高于汇编语言级别的语言编写,在这里您可以编写以下内容

values.sum
或(如果未提供金额)

当您需要时,可以使用列表理解、地图/收集等

您是否发现在这样的环境中仍然需要可变变量?如果需要,原因是什么

为了澄清,我不是要求背诵对SSA表格的反对意见,而是要求列举那些反对意见适用的具体例子。我正在寻找一些代码,这些代码对于可变变量来说是清晰简洁的,如果没有它们就无法编写

到目前为止,我最喜欢的例子(以及我对它们的最大异议):

  • Paul Johnson的答案,当你考虑到大O约束时,这是非常有力的。但是,正如catulahoops所指出的那样,big-O问题与SSA问题无关,而是与具有可变数据类型有关,撇开这一点,算法可以在SSA中写得相当清楚:

     shuffle(Lst) ->
         array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
     shuffle(Array, 0) -> Array;
     shuffle(Array, N) ->
         K = random:uniform(N) - 1,
         Ek = array:get(K, Array),
         En = array:get(N, Array),
         shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
    
  • jpalecek的例子:

  • Princess关于用不可变结构实现O(1)队列的困难的观点很有意思(很可能为一个引人注目的例子提供了基础),但正如前面所述,它基本上是关于数据结构的可变性,而不是直接关于多重赋值问题

  • 我对埃拉托什尼的回答很感兴趣,但并不信服。在他引用的论文中给出的适当的大O,拉尽可能多的素数生成器,无论是否使用SSA,看起来都不容易正确实现


  • 谢谢大家的努力。由于大多数答案被证明是1)基于可变数据结构,而不是基于单个赋值,以及2)在某种程度上,它们是关于单个赋值形式的,很容易被本领域技术人员反驳,因此我将从我的演讲和/或重组中划出一条线(可能会把它作为一个讨论主题放在备份中,以防在我没时间之前就说不出话来)


    再次感谢。

    当您需要对大型数据结构进行小的更改时,该怎么办?您并不是真的希望每次修改几个元素时都复制整个数组或大型类。

    如果您想进行学术论证,那么从技术上讲,当然不需要多次指定变量。证明不是这样的所有的代码都可以用形式表示。事实上,对于许多静态和动态分析来说,这是最有用的形式

    同时,有一些原因使我们不能从SSA表单开始编写代码:

  • 以这种方式编写代码通常需要更多的语句(或更多的代码行)。简洁是有价值的
  • 它几乎总是效率较低。是的,我知道你说的是更高级的语言——一个公平的范围——但即使在Java和C#的世界里,远离汇编,速度也很重要。很少有应用程序与速度无关
  • 这并不容易理解。虽然SSA在数学意义上“更简单”,但它从常识中更抽象,这在现实编程中很重要。如果你必须非常聪明地摸索它,那么它在编程中就没有任何位置
  • 即使在上面的示例中,也很容易戳破漏洞。以您的
    案例
    语句为例。如果有一个管理选项决定是否允许
    '*'
    ,并有一个单独的选项决定是否允许
    '?'
    呢?此外,整数案例不允许为零,除非用户具有系统权限,否则所有的好的

    这是一个更真实的例子,有分支和条件。你能把它写成一个“语句”吗?如果可以,是你的“语句”与许多单独的语句真的不同吗?如果不是,您需要多少临时的只写变量?这种情况是否比只有一个变量要好得多?

    回应Jason--


    我从来没有发现过这样的情况。虽然你总是可以发明新的名称,比如在转换为SSA形式时,我实际上发现每个值都有自己的名称是很容易和自然的。像Haskell这样的语言为我提供了很多选择,关于命名哪些值,以及放置名称绑定的两个不同位置(
    let
    where
    )。我觉得单一的作业形式很自然,一点也不难

    我偶尔会错过在堆上有指向可变对象的指针。但是这些东西没有名字,所以这不是同一个问题。(我还发现,当我在堆上使用可变对象时,我倾向于编写更多的bug!)

    本地(方法)变量当然不必被赋值两次。但即使在函数式编程中,重新赋值也是允许的。它改变了(部分)不允许的值。正如dsimcha已经回答的,对于非常大的结构(可能在应用程序的根上)对我来说,替换整个结构似乎不可行。想想看。应用程序的状态最终都由应用程序的入口点方法包含。如果绝对没有任何状态可以不被替换而更改,那么
    x = if a > b then a else b
    
    n = case s 
      /^\d*$/ : s.to_int
      ''      : 0
      '*'     : a.length
      '?'     : a.length.random
      else    fail "I don't know how many you want"
    
     shuffle(Lst) ->
         array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
     shuffle(Array, 0) -> Array;
     shuffle(Array, N) ->
         K = random:uniform(N) - 1,
         Ek = array:get(K, Array),
         En = array:get(N, Array),
         shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
    
    def area(figure : List[Point]) : Float = {
      if(figure.empty) return 0
      val last = figure(0)
      var first= figure(0)
      val ret = 0
      for (pt <- figure) {
        ret+=crossprod(last - first, pt - first)
        last = pt
      }
      ret
    }
    
    def area(figure : List[Point]) : Float = {
        if figure.length < 3
            0
          else
            var a = figure(0)
            var b = figure(1)
            var c = figure(2)
            if figure.length == 3
                magnitude(crossproduct(b-a,c-a))
              else 
                foldLeft((0,a,b))(figure.rest)) { 
                   ((t,a,b),c) => (t+area([a,b,c]),a,c)
                   }
    
    def area([])    = 0.0   # An empty figure has no area
    def area([_])   = 0.0   # ...nor does a point
    def area([_,_]) = 0.0   # ...or a line segment
    def area([a,b,c]) =     # The area of a triangle can be found directly
        magnitude(crossproduct(b-a,c-a))
    def area(figure) =      # For larger figures, reduce to triangles and sum
        as_triangles(figure).collect(area).sum
    
    def as_triangles([])      = []  # No triangles without at least three points
    def as_triangles([_])     = []
    def as_triangles([_,_])   = []
    def as_triangles([a,b,c | rest) = [[a,b,c] | as_triangles([a,c | rest])]
    
    function forbidden_input?(s)
        (s = '?' and not administration.qmark_ok) ||
        (s = '*' and not administration.stat_ok)  ||
        (s = '0' and not 'root node visible' in system.permissions_for(current_user))
    
    n = if forbidden_input?(s)
        fail "'" + s + "' is not allowed."
      else
        case s
          /^\d*$/ : s.to_int
          ''      : 0
          '*'     : a.length
          '?'     : a.length.random
          else    fail "I don't know how many you want"
    
    start = self.offset%n
    if start:
        start = n-start
    
    def quant[A](x : List[A], q : A) = {
      var tmp : A=0
      for (el <- x) { tmp+= el; if(tmp > q) return el; }
      // throw exception here, there is no prefix of the list with sum > q
    }
    
    def area(figure : List[Point]) : Float = {
      if(figure.empty) return 0
      val last = figure(0)
      var first= figure(0)
      val ret = 0
      for (pt <- figure) {
        ret+=crossprod(last - first, pt - first)
        last = pt
      }
      ret
    }
    
    -- | Implementation of the random swap algorithm for shuffling.  Reads a list
    -- into a mutable ST array, shuffles it in place, and reads out the result
    -- as a list.
    
    module Data.Shuffle (shuffle) where
    
    
    import Control.Monad
    import Control.Monad.ST
    import Data.Array.ST
    import Data.STRef
    import System.Random
    
    -- | Shuffle a value based on a random seed.
    shuffle :: (RandomGen g) => g -> [a] -> [a]
    shuffle _ [] = []
    shuffle g xs = 
        runST $ do
          sg <- newSTRef g
          let n = length xs
          v <- newListArray (1, n) xs
          mapM_ (shuffle1 sg v) [1..n]
          getElems v
    
    -- Internal function to swap element i with a random element at or above it.
    shuffle1 :: (RandomGen g) => STRef s g -> STArray s Int a -> Int -> ST s ()
    shuffle1 sg v i = do
      (_, n) <- getBounds v
      r <- getRnd sg $ randomR (i, n)
      when (r /= i) $ do
        vi <- readArray v i
        vr <- readArray v r
        writeArray v i vr
        writeArray v r vi
    
    
    -- Internal function for using random numbers
    getRnd :: (RandomGen g) => STRef s g -> (g -> (a, g)) -> ST s a
    getRnd sg f = do
      g1 <- readSTRef sg
      let (v, g2) = f g1
      writeSTRef sg g2
      return v
    
     shuffle(Lst) ->
         array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
    
     shuffle(Array, 0) -> Array;
     shuffle(Array, N) ->
         K = random:uniform(N) - 1,
         Ek = array:get(K, Array),
         En = array:get(N, Array),
         shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
    
    module Vector =
        type point =
            { x : float; y : float}
            with
                static member ( + ) ((p1 : point), (p2 : point)) =
                    { x = p1.x + p2.x;
                      y = p1.y + p2.y;}
    
                static member ( * ) ((p : point), (scalar : float)) =
                    { x = p.x * scalar;
                      y = p.y * scalar;}
    
                static member ( - ) ((p1 : point), (p2 : point)) = 
                    { x = p1.x - p2.x;
                      y = p1.y - p2.y;}
    
        let empty = { x = 0.; y = 0.;}
        let to_tuple2 (p : point) = (p.x, p.y)
        let from_tuple2 (x, y) = { x = x; y = y;}
        let crossproduct (p1 : point) (p2 : point) =
            { x = p1.x * p2.y; y = -p1.y * p2.x }
    
    let area (figure : point list) =
        figure
        |> Seq.map to_tuple2
        |> Seq.fold
            (fun (sum, (a, b)) (c, d) -> (sum + a*d - b*c, (c, d) ) )
            (0., to_tuple2 (List.hd figure))
        |> fun (sum, _) -> abs(sum) / 2.0
    
    let area2 (figure : point list) =
        figure
        |> Seq.fold
            (fun (acc, prev) cur -> (acc + (crossproduct prev cur), cur))
            (empty, List.hd figure)
        |> fun (acc, _) -> abs(acc.x + acc.y) / 2.0