Documentation
¶
Overview ¶
Example (Read_basicUsage) ¶
Example_read_basicUsage demonstrates basic usage of the Read function to read data from a file with automatic resource cleanup.
package main
import (
"fmt"
"io"
"os"
FL "github.com/IBM/fp-go/v2/file"
F "github.com/IBM/fp-go/v2/function"
I "github.com/IBM/fp-go/v2/io"
"github.com/IBM/fp-go/v2/ioresult"
"github.com/IBM/fp-go/v2/ioresult/file"
)
func main() {
// Create a temporary file for demonstration
tmpFile, err := os.CreateTemp("", "example-*.txt")
if err != nil {
fmt.Printf("Error creating temp file: %v\n", err)
return
}
defer os.Remove(tmpFile.Name())
// Write some test data
testData := "Hello, World! This is a test file."
if _, err := tmpFile.WriteString(testData); err != nil {
fmt.Printf("Error writing to temp file: %v\n", err)
return
}
tmpFile.Close()
// Define a reader function that reads the full file content
readAll := F.Flow2(
FL.ToReader[*os.File],
ioresult.Eitherize1(io.ReadAll),
)
content := F.Pipe2(
readAll,
file.Read[[]byte](file.Open(tmpFile.Name())),
ioresult.TapIOK(I.Printf[[]byte]("%s\n")),
)
content()
}
Output: Hello, World! This is a test file.
Index ¶
- Variables
- type IOResult
- func Close[C io.Closer](c C) IOResult[struct{}]
- func Mkdir(path string, perm os.FileMode) IOResult[string]
- func MkdirAll(path string, perm os.FileMode) IOResult[string]
- func ReadAll[R io.ReadCloser](acquire IOResult[R]) IOResult[[]byte]
- func Remove(name string) IOResult[string]
- func WithTempFile[A any](f Kleisli[*os.File, A]) IOResult[A]
- type Kleisli
- type Operator
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // Open opens a file for reading Open = file.Open // Create opens a file for writing Create = file.Create // ReadFile reads the context of a file ReadFile = file.ReadFile // Stat returns [FileInfo] object Stat = file.Stat // UserCacheDir returns an [IOResult] that resolves to the default root directory // to use for user-specific cached data. Users should create their own application-specific // subdirectory within this one and use that. // // On Unix systems, it returns $XDG_CACHE_HOME as specified by // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if // non-empty, else $HOME/.cache. // On Darwin, it returns $HOME/Library/Caches. // On Windows, it returns %LocalAppData%. // On Plan 9, it returns $home/lib/cache. // // If the location cannot be determined (for example, $HOME is not defined), // then it will return an error wrapped in [Err]. UserCacheDir = file.UserCacheDir // UserConfigDir returns an [IOResult] that resolves to the default root directory // to use for user-specific configuration data. Users should create their own // application-specific subdirectory within this one and use that. // // On Unix systems, it returns $XDG_CONFIG_HOME as specified by // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if // non-empty, else $HOME/.config. // On Darwin, it returns $HOME/Library/Application Support. // On Windows, it returns %AppData%. // On Plan 9, it returns $home/lib. // // If the location cannot be determined (for example, $HOME is not defined), // then it will return an error wrapped in [Err]. UserConfigDir = file.UserConfigDir // UserHomeDir returns an [IOResult] that resolves to the current user's home directory. // // On Unix, including macOS, it returns the $HOME environment variable. // On Windows, it returns %USERPROFILE%. // On Plan 9, it returns the $home environment variable. // // If the location cannot be determined (for example, $HOME is not defined), // then it will return an error wrapped in [Err]. UserHomeDir = file.UserHomeDir )
var ( // CreateTemp creates a temporary file with proper parametrization. // It is an alias for ioeither.file.CreateTemp which wraps os.CreateTemp // in an IOResult context for functional composition. // // This function takes a directory and pattern parameter and returns an IOResult // that produces a temporary file handle when executed. // // Parameters: // - dir: directory where the temporary file should be created (empty string uses default temp dir) // - pattern: filename pattern with optional '*' placeholder for random suffix // // Returns: // IOResult[*os.File] that when executed creates and returns a temporary file handle // // Example: // tempFile := CreateTemp("", "myapp-*.tmp") // result := tempFile() // file, err := E.UnwrapError(result) // if err != nil { // log.Fatal(err) // } // defer file.Close() CreateTemp = file.CreateTemp )
Functions ¶
This section is empty.
Types ¶
type IOResult ¶
IOResult represents a synchronous computation that may fail, returning a Result type. It is an alias for ioresult.IOResult[T] which is equivalent to IO[Result[T]].
IOResult[T] is a function that when executed returns Result[T], which is Either[error, T]. This provides a functional approach to handling IO operations that may fail, with automatic resource management and composable error handling.
Example:
var readFile IOResult[[]byte] = func() Result[[]byte] {
data, err := os.ReadFile("config.json")
return result.TryCatchError(data, err)
}
// Execute the IO operation
result := readFile()
data, err := E.UnwrapError(result)
func MkdirAll ¶
MkdirAll create a sequence of directories, see os.MkdirAll
func ReadAll ¶
func ReadAll[R io.ReadCloser](acquire IOResult[R]) IOResult[[]byte]
ReadAll uses a generator function to create a stream, reads it and closes it
func WithTempFile ¶
WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then automatically closes and removes the temp file.
This function provides safe temporary file management by:
- Creating a temporary file with sensible defaults
- Passing the file handle to the provided callback function
- Ensuring the file is closed and removed, even if the callback fails
Type Parameters:
- A: The type of result produced by the callback function
Parameters:
- f: A Kleisli function that takes a *os.File and returns an IOResult[A]
Returns:
IOResult[A] that when executed creates a temp file, runs the callback, and cleans up the file regardless of success or failure
Example - Writing and reading from a temporary file:
import (
"io"
"os"
E "github.com/IBM/fp-go/v2/either"
"github.com/IBM/fp-go/v2/ioresult"
"github.com/IBM/fp-go/v2/ioresult/file"
)
// Write data to temp file and return the number of bytes written
writeToTemp := func(f *os.File) ioresult.IOResult[int] {
return ioresult.TryCatchError(func() (int, error) {
data := []byte("Hello, temporary world!")
return f.Write(data)
})
}
result := file.WithTempFile(writeToTemp)
bytesWritten, err := E.UnwrapError(result())
if err != nil {
log.Fatal(err)
}
fmt.Printf("Wrote %d bytes to temporary file\n", bytesWritten)
Example - Processing data through a temporary file:
processData := func(data []byte) ioresult.IOResult[string] {
return file.WithTempFile(func(f *os.File) ioresult.IOResult[string] {
return ioresult.TryCatchError(func() (string, error) {
// Write data to temp file
if _, err := f.Write(data); err != nil {
return "", err
}
// Seek back to beginning
if _, err := f.Seek(0, 0); err != nil {
return "", err
}
// Read and process
processed, err := io.ReadAll(f)
if err != nil {
return "", err
}
return strings.ToUpper(string(processed)), nil
})
})
}
result := processData([]byte("hello world"))
output, err := E.UnwrapError(result())
if err != nil {
log.Fatal(err)
}
fmt.Println(output) // "HELLO WORLD"
The temporary file is guaranteed to be cleaned up even if the callback function panics or returns an error, providing safe resource management in a functional style.
type Kleisli ¶
Kleisli represents a function that takes a value of type A and returns an IOResult[B]. It is an alias for ioresult.Kleisli[A, B] which is equivalent to Reader[A, IOResult[B]].
Kleisli functions are the building blocks of monadic composition in the IOResult context. They allow for chaining operations that may fail while maintaining functional purity.
Example:
// A Kleisli function that reads from a file handle
var readAll Kleisli[*os.File, []byte] = func(f *os.File) IOResult[[]byte] {
return TryCatchError(func() ([]byte, error) {
return io.ReadAll(f)
})
}
// Can be composed with other Kleisli functions
var processFile = F.Pipe1(
file.Open("data.txt"),
file.Read[[]byte, *os.File],
)(readAll)
func Read ¶
func Read[R any, RD io.ReadCloser](acquire IOResult[RD]) Kleisli[Kleisli[RD, R], R]
Read uses a generator function to create a stream, reads data from it using a provided reader function, and ensures the stream is properly closed after reading.
This function provides safe resource management for reading operations by:
- Acquiring a ReadCloser resource using the provided acquire function
- Applying a reader function to extract data from the resource
- Ensuring the resource is closed, even if an error occurs during reading
Type Parameters:
- R: The type of data to be read from the stream
- RD: The type of the ReadCloser resource (must implement io.ReadCloser)
Parameters:
- acquire: An IOResult that produces the ReadCloser resource
Returns:
A Kleisli function that takes a reader function (which transforms RD to R) and returns an IOResult that produces the read result R or an error.
The key difference from ioeither.Read is that this returns IOResult[R] which is IO[Result[R]], representing a computation that returns a Result type (tuple of value and error) rather than an Either type.
Example - Reading first N bytes from a file:
import (
"os"
"io"
F "github.com/IBM/fp-go/v2/function"
R "github.com/IBM/fp-go/v2/result"
"github.com/IBM/fp-go/v2/ioresult"
"github.com/IBM/fp-go/v2/ioresult/file"
)
// Read first 10 bytes from a file
readFirst10 := func(f *os.File) ioresult.IOResult[[]byte] {
return ioresult.TryCatch(func() ([]byte, error) {
buf := make([]byte, 10)
n, err := f.Read(buf)
return buf[:n], err
})
}
result := F.Pipe1(
file.Open("data.txt"),
file.Read[[]byte, *os.File],
)(readFirst10)
// Execute the IO operation to get the Result
res := result()
data, err := res() // Result is a tuple function
if err != nil {
log.Fatal(err)
}
fmt.Printf("Read: %s\n", data)
Example - Using with Result combinators:
result := F.Pipe1(
file.Open("config.json"),
file.Read[[]byte, *os.File],
)(readFirst10)
// Chain operations using Result combinators
processed := F.Pipe2(
result,
ioresult.Map(func(data []byte) string {
return string(data)
}),
ioresult.ChainFirst(func(s string) ioresult.IOResult[any] {
return ioresult.Of[any](fmt.Printf("Read: %s\n", s))
}),
)
res := processed()
str, err := res()
if err != nil {
log.Fatal(err)
}
The Read function ensures that the file is closed even if the reading operation fails, providing safe and composable resource management in a functional style.
type Operator ¶
Operator represents a function that transforms one IOResult into another. It is an alias for ioresult.Operator[A, B] which is equivalent to Kleisli[IOResult[A], B].
Operators are used for transforming and composing IOResult values, providing a way to build complex data processing pipelines while maintaining error handling semantics.
Example:
// An operator that converts bytes to string
var bytesToString Operator[[]byte, string] = Map(func(data []byte) string {
return string(data)
})
// An operator that validates JSON
var validateJSON Operator[string, map[string]interface{}] = ChainEitherK(
func(s string) Result[map[string]interface{}] {
var result map[string]interface{}
err := json.Unmarshal([]byte(s), &result)
return result.TryCatchError(result, err)
},
)
// Compose operators in a pipeline
var processJSON = F.Pipe2(
readFileOperation,
bytesToString,
validateJSON,
)