Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
fi
shell: bash
- name: Install R package dependencies
run: Rscript -e "install.packages(c('tseries', 'zoo'), repos = 'https://cran.r-project.org')"
run: Rscript -e "install.packages(c('tseries', 'zoo', 'ggplot2', 'svglite'), repos = 'https://cran.r-project.org')"
shell: bash
- name: Setup .NET
uses: actions/setup-dotnet@v1
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
fi
shell: bash
- name: Install R package dependencies
run: Rscript -e "install.packages(c('tseries', 'zoo'), repos = 'https://cran.r-project.org')"
run: Rscript -e "install.packages(c('tseries', 'zoo', 'ggplot2', , 'svglite'), repos = 'https://cran.r-project.org')"
shell: bash
- name: Setup .NET
uses: actions/setup-dotnet@v1
Expand All @@ -53,6 +53,7 @@ jobs:
- name: Build
run: dotnet fsi build.fsx
- name: Deploy documentation from master
if: matrix.os == 'macos-latest'
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
RProvider License
=================

Copyright (c) 2012–2026, RProvider Contributors
Copyright (c) 2012, BlueMountain Capital Management LLC
Copyright (c) 2021 - 2026, Andrew C. Martin

All rights reserved.

Expand Down
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* 3.0.0 - semantic types, RBridge, graphics module (svg outputs), new fsdocs template.
* 3.0.0-alpha1 - replaced R.NET with RBridge, and updated to latest type provider SDK
* 2.1.0 - new feature: ? and => operators; and locale fix for regions with comma number seperator
* 2.0.3 - Include built-in FSI printer module
Expand Down
6 changes: 3 additions & 3 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ let projectSummary =

let projectDescription =
"""
An F# Type Provider providing strongly typed access to the R statistical package.
An F# Type Provider providing strongly typed access to the R statistical language.
The type provider automatically discovers available R packages and makes them
easily accessible from F#, so you can easily call powerful packages and
visualization libraries from code running on the .NET platform."""
Expand Down Expand Up @@ -241,7 +241,7 @@ Target.create
sprintf "<PackageIconUrl>%s/master/docs/content/logo.png</PackageIconUrl>" repositoryContentUrl
sprintf "<PackageTags>%s</PackageTags>" tags
sprintf "<Version>%s</Version>" release.NugetVersion
sprintf "<FsDocsLogoSource>%s/master/docs/img/logo.png</FsDocsLogoSource>" repositoryContentUrl
sprintf "<FsDocsLogoSource>img/logo.png</FsDocsLogoSource>"
sprintf "<FsDocsLicenseLink>%s/blob/master/LICENSE.md</FsDocsLicenseLink>" repositoryUrl
sprintf "<FsDocsReleaseNotesLink>%s/blob/master/RELEASE_NOTES.md</FsDocsReleaseNotesLink>" repositoryUrl
"<FsDocsWarnOnMissingDocs>true</FsDocsWarnOnMissingDocs>"
Expand All @@ -258,7 +258,7 @@ Target.create
DotNet.exec
id
"fsdocs"
("build --clean --properties Configuration=Release --parameters fsdocs-package-version "
("build --clean --eval --properties Configuration=Release --parameters fsdocs-package-version "
+ release.NugetVersion)
|> ignore)

Expand Down
152 changes: 147 additions & 5 deletions docs/expressions.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,146 @@ RProvider represents R objects and values through an `RExpr` type. RProvider inc
open RProvider
open RProvider.Operators

open RProvider.``base``
open RProvider.datasets
open RProvider.stats

(**
Next, let's use a sample R dataframe to demonstrate core R expression functions.
*)

let df = R.penguins

(**
Note: in most cases, there are equivalent functions available using either the module (`RExpr.*`) or using dot notation as we preference below.

### Inpecting a value

You may print the expression identically to using R print() using the .Print function or `RExpr.printToString`.
*)

df.Print()

(**
When using F# interactive (fsi), you may register a pretty-printer to print R values automatically into the terminal using `fsi.AddPrinter FSIPrinters.rValue`.

We can also inspect the 'semantic type' - the standard R shape - of the R expression.
The possible shapes are listed in the `Runtime.RTypes.RSemanticType` discriminated union.
*)

df.Type
(*** include-it ***)

(**
Similarly, you may retrieve the classes of an R object using the classes property.
*)

df.Class
(*** include-it ***)

(**
#### Printing R values to the console (F# interactive)

Add this line to your script to tell F# interactive how to print out
the values of R objects:

[lang=fsharp]
fsi.AddPrinter FSIPrinters.rValue


### Extracting values (R -> F#)

We can extract a value from R memory space into to F# primitive values in two ways: type-specific
or default type. For more information, see [passing data](passing-data.html).

For example, let's extract the bill length column from the penguin dataset using the `RExpr` directly (without using the semantic types layer). To access the column, we can use the `?` operator; see [operators](operators.html) for details.
*)

let billLength = df?bill_len
let billVal = df?bill_len |> RExpr.getValue<float[]>

(**
#### Extracting using the semantic R types layer
It is also possible to extract values through semantic types. Each semantic type has its own extraction functions specific to the type. For more information, see [semantic R types](semantic-types.html).

Here, we can show how to extract a factor column using a type-safe pattern matching approach.
*)

let speciesFactorSafe =
match df?species.TryAsTyped with
| Some t ->
match t with
| Runtime.RTypes.FactorInR f -> f.AsStringVector.Value
| _ -> [||]
| _ -> [||]

(**
We can also do the same thing without try methods if we are certain of the type:
*)

let speciesFactor = df?species.AsFactor().AsStringVector.Value
speciesFactor
(*** include-it ***)

(**
*Note: Older RProvider versions contained a plugin system to register custom converters between .NET types and R types. This has been removed. The new preferred approach is to convert explicitly from semantic type wrappers. For example, an F# data frame library like Deedle could implement a custom conversion function from RProvider's `DataFrame` type.*

### Viewing as an R semantic type

A set of functions enable viewing an `RExpr` as RProvider's R semantic type wrappers.

### Quick access to common properties

The `RExpr` type has members for quick access into common required fields or properties of R objects. These are mirrored in the `RExpr`, which are easier to call with forward pipes for example.

#### Vectors

You can quickly access a single value within a vector using `.ValueAt` and the index.
*)

let v = [ 0.1 .. 3.5 ] |> R.c

let y : Runtime.RTypes.RScalar<1> = v.ValueAt 0
y.AsReal().FromR.Value

let z : Runtime.RTypes.RScalar<1> = v |> RExpr.typedVectorByIndex 0
z.AsReal().FromR.Value

(**
#### Lists and list-based objects

S3 objects in R are basic R objects, but with a class attribute attached.
More often than not, they are lists.

# S4 classes
There are multiple quick-access methods to list items:

* Using the ? operator from `RProvider.Operators`.
* Using the `RExpr.listItem` function.
*)

let x = 10.
let summary = R.binom_test(x, 100., 0.5) // alternative = true

summary?``p.value``.FromR<float>()
summary?statistic.FromR<float>()

RExpr.listItem "p.value" summary

(**
#### S4 objects (slots)

For this example, let's set up an S4 class and object from scratch:
*)

R.eval "setClass('testclass', representation(foo='character', bar='integer'))"
let s4 = R.eval "new('testclass', foo='s4', bar=1:4)"
R.parse(text = "setClass('testclass', representation(foo='character', bar='integer'))") |> R.eval
let s4 = R.parse(text = "new('testclass', foo='s4', bar=1:4)") |> R.eval
s4.Print()
(*** include-it ***)

(**
You can find out if there are slots using the `slots` and `trySlots` functions:
*)

s4 |> RExpr.slots
s4 |> RExpr.trySlots
R.mtcars |> RExpr.trySlots

(**
Expand All @@ -58,3 +178,25 @@ You can access slot values similarly with the `slot` and `trySlot` functions:
s4 |> RExpr.slot "foo"
s4 |> RExpr.trySlot "foo"
s4 |> RExpr.trySlot "doesntexist"

(**
## Parallel processing

R itself is not thread-safe. Most R parallel processing libraries focus on running multiple R processes and coordinating work and values between them.

When using RProvider, you may use R from one or many threads. However, the underlying R engine being used is a single R instance. Internally, *RBridge* uses a concurrent queue to process incoming work. You will only gain the perception of multi-threading but none of the speed advantage when consuming R functions.
*)

[| 1 .. 10 |]
|> Array.Parallel.map(fun i -> (R.sqrt i).AsScalar().AsReal().FromR.Value)
(*** include-it ***)

[| 1 .. 10 |]
|> Array.map(fun i -> (R.sqrt i).AsScalar().AsReal().FromR.Value)
(*** include-it ***)

(**
As can be seen, the results are identical.

**Important**. Although *pure* functions return identical results, impure functions will not. The internal R instance is sharing it's environment, so you may cross contaminate.
*)
Binary file removed docs/img/bmc.png
Binary file not shown.
Binary file removed docs/img/vscode.gif
Binary file not shown.
86 changes: 86 additions & 0 deletions docs/index.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
(*** condition: prepare ***)
#nowarn "211"
#r "nuget: RProvider, 0.0.1-local"
(*** condition: fsx ***)
#if FSX
#r "nuget: RProvider,{{package-version}}"
#endif // FSX
(*** condition: ipynb ***)
#if IPYNB
#r "nuget: RProvider,{{package-version}}"
#endif // IPYNB

(**
F# R Type Provider
=======

**A typed interop layer that embeds R within F#.**

The F# Type Provider enables interoperability between F# and [R](http://www.r-project.org/) through strongly-typed representations of F# types. The Type Provider discovers R packages that are available in an R installation and makes them available as namespaces in F#.

From F#, you can call any R function, run statistical analyses, generate plots, and work with R objects interactively. This lets you combine R’s extensive statistical and visualisation ecosystem with F#'s succinct and expressive type system — including type providers, units of measure, and functional data pipelines.

The below example shows a simple base R example within F#:
*)

open RProvider
open RProvider.stats

let x = [ 1. .. 5. ] |> R.c
let y = [ 1.2; 2.1; 2.9; 4.5; 4.8 ] |> R.c

// Run a correlation test in R
let result = R.cor_test(x, y)

// Extract results into F#
let pValue = result |> RExpr.listItem "p.value" |> RExpr.getValue<float>
let statistic = result |> RExpr.listItem "statistic" |> RExpr.getValue<float>
let estimate = result |> RExpr.listItem "estimate" |> RExpr.getValue<float>

printfn "Correlation estimate: %g\nTest statistic: %g\np-value: %g" estimate statistic pValue
(*** include-output ***)

(**
The above example is run through F# interactive (`dotnet fsi`).

## Using the R Type Provider

**Prerequisites**. R 4.5.0 or higher, .NET 10 or higher, and the R_HOME environment variable set. [More info](requirements.html).

In an F# script:
```fsharp
#r "nuget:RProvider"

open RProvider
```

To add to a .NET project, from the terminal:
```
dotnet add package RProvider
```

## What are R and F#?

[F#](http://fsharp.org) is a multi-paradigm language
that supports functional, object and imperative programming,
with the emphasis on functional-first programming. F# runs on the .NET runtime and is a compiled,
statically typed language with a strong type system and type inference.
F# is a general purpose programming language, and is particularly well-suited for scientific/numerical computing.

[R](http://www.r-project.org/) is a domain-specific language for statistical computing.
R has a rich ecosystem of community-developed packages across scientific disciplines.
R has many packages for publication-quality graphics, such as ggplot.
R is an interpreted, dynamically typed language for data exploration that is typically used
R-specific IDEs like [RStudio](http://www.rstudio.com/).


## Contributing and copyright

The project was originally developed by [BlueMountain Capital](https://www.bluemountaincapital.com/), and has since been developed and open-source contributors.

The project is hosted on [GitHub][gh] where you can [report issues][issues], fork the project and submit pull requests.

[gh]: https://github.com/fslaborg/RProvider
[issues]: https://github.com/fslaborg/RProvider/issues
[license]: https://github.com/fslaborg/RProvider/blob/master/LICENSE.md
*)
Loading
Loading