powershell - 在PowerShell中使用Monad?

标签 powershell functional-programming

我有以下代码

function Get($url) {
    $x = Invoke-RestMethod $url 
    # ....
    $result # return a json which some values (id, name, color) and a list
}

Get "http://...." |
% {
    $id = $_.id
    $url = "${$_.url}/xxx"
    Get $ur  |
    % {
        $name = $_.name
        $url = $_.url
        Get $url | 
        % {
            $color = $_.color
            $url = $_.url

            Get $url | % {
                # other layer omitted
            }
        }
    }
}

代码看起来很糟糕。似乎嵌入式层应该由monad解决。在PowerShell中有没有办法做到这一点?

下面显示了伪F#代码。
myMonad {
    let! (id1, _,     _,      urls1, _    ) = Get ["http://..."]
    let! (_,   name2, _,      urls2, _    ) = Get urls1
    let! (_,   _,     color3, urls3, names) = Get urls2
    // ....
    printfn "%d %s %s %A" id1, name2, color3, names
}

最佳答案

尽管PowerShell具有一些功能特性,并且它的许多构造和动态特性允许您模拟功能特性,但PowerShell显然不是一种功能语言:

下面的代码定义了一个名为recurse的递归和聚合函数,该函数可以按如下方式调用Get函数,以便通过返回的每个对象的Id属性从对Name的递归调用中聚合ColorGet.URL的属性:

recurse -Function  Get                 <# target function #> `
        -Argument  http://example.org  <# input URL #> `
        -RecurseOn URL                 <# what result property to recurse on #> `
        -PropertyNames Id, Name, Color <# what properties to aggregate successively, 
                                          in each iteration #>
recurse源代码和示例代码:
# A fairly generic recurse-and-aggregate function that aggregates properties from
# result objects from recursive calls to a given function based on a single result property.
function recurse($Function, $Arguments, $RecurseOn, $PropertyNames, $outProperties = [ordered] @{ }) {

  # Call the target function with the specified arguments.
  $result = & $Function $Arguments

  # Split into the names of the current and the remaining properties to aggregate.
  $propName, $remainingPropNames = $PropertyNames

  # Add the value of the current property of interest to the output hashtable, if present.
  if ($null -ne $result.$propName) {
    if ($outProperties.Contains($propName)) { # not the first value
      if ($outProperties.$propName -is [array]) { # already an array -> "extend" the array.
        $outProperties.$propName += $result.$propName
      }
      else { # not an array yet -> convert to array, with the previous value and the new one as the elements. 
        $outProperties.$propName = $outProperties.$propName, $result.$propName
      }
    }
    else { # first value -> assign as-is
      $outProperties.$propName = $result.$propName
    }
  }

  if ($remainingPropNames) {
    # Recurse on the value(s) of the property specfied with -RecurseOn
    foreach ($newArgument in $result.$RecurseOn) {
      $null = recurse -Function $function -Argument $newArgument -RecurseOn $RecurseOn -PropertyNames $remainingPropNames -outProperties $outProperties
    }
  }

  # Return the aggregated properties.
  $outProperties

}

# Sample input function:
# It makes a REST call to the given URL and returns the
# result object.
function Get($url) {
  Write-Host "Get $url"
  $id = 1
  $name = ''
  $color = ''

  if ($url -eq 'http://example.org') { 
      $urls = 'http://example.org/1', 'http://example.org/2'
      $id = 1
  }
  elseif ($url -match 'http://example.org/\d$') { 
      $urls = "$url/a", "$url/b" 
      $name = 'test'
  }
  elseif ($url -match 'http://example.org/\d/a') {
      $urls = '...'
      $name = 'test'
      $color = "[color of $url] #1", "[color of $url] #2"
  }
  elseif ($url -match 'http://example.org/\d/b') {
      $urls = '...'
      $name = 'test'
      $color = "[color of $url] #1", "[color of $url] #2"
  }

  [pscustomobject] @{
      URL = $urls
      Id  = $id
      Name = $name
      Color = $color
  }
}

# Call the recurse-and-aggregate function, passing it the name of the Get() 
# function, an input URL, what result property to recurse on, and a list of properties to aggregate.
# The output is an ordered hashtable containing the aggregated property values.
recurse -Function  Get                 <# target function #> `
        -Argument  http://example.org  <# input URL #> `
        -RecurseOn URL                 <# what result property to recurse on #> `
        -PropertyNames Id, Name, Color <# what properties to aggregate successively, 
                                          in each iteration #>

以上 yield :

Name                           Value
----                           -----
Id                             1
Name                           {test, test}
Color                          {[color of http://example.org/1/a] #1, [color of http://example.org/1/a] #2, [color of http://example.org/1/b] #1, [color of htt…

关于powershell - 在PowerShell中使用Monad?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57914838/

相关文章:

javascript - 等效于 JavaScript 中的 Scala View

java - 使用 Slick 获得 Rep[Optional[...]] 的产量

string - 如何在Powershell中搜索多个文件中的字符串并返回文件名?

azure - 使用 Powershell 而不是 Bash 请求 Azure Databricks 访问 token

javascript - 将json转换为其他json结构

javascript - 使用 lodash 柯里化(Currying)翻转函数 - 有限制吗?

powershell - 在 NuGet 包安装/初始化期间运行的 Powershell 脚本有哪些安全限制?

c# - 如何向 Azure C# SecretClient 提供凭据 (DefaultAzureCredential)?它似乎忽略凭据和 RBAC 并抛出 403

powershell - 如何使用Powershell配置新的DCOM RunAs用户

functional-programming - 多参数和嵌套函数的函数组合