Skip to content

Instantly share code, notes, and snippets.

@mahdiPourkazemi
Created August 9, 2025 14:56
Show Gist options
  • Save mahdiPourkazemi/4a26c25c6adf1a2dd70b1c78663d075e to your computer and use it in GitHub Desktop.
Save mahdiPourkazemi/4a26c25c6adf1a2dd70b1c78663d075e to your computer and use it in GitHub Desktop.
Function Composition simple and with flow
@Composable
fun PriceScreen() {
val originalPrice = 150.0
val addTax = { price: Double -> price * 1.08 }
val applyDiscount = { price: Double -> price * 0.85 }
val roundPrice = { price: Double -> kotlin.math.round(price) }
val finalPrice = processPrice(originalPrice, applyDiscount, addTax, roundPrice)
Text(
text = "Final Price: $finalPrice",
style = MaterialTheme.typography.headlineMedium
)
}
fun processPrice(
originalPrice: Double,
vararg operations: (Double) -> Double
): String {
var result = originalPrice
operations.forEach { operation ->
result = operation(result)
}
return "$${"%.2f".format(result)}"
}
//#################################################################
// --- عملیات‌ها ---
val addTax: (Double) -> Double = { price -> price * 1.08 }
val applyDiscount: (Double) -> Double = { price -> price * 0.85 }
val roundPrice: (Double) -> Double = { price -> kotlin.math.round(price) }
// فرمت کردن قیمت
fun Double.formatCurrency(): String =
"$${"%.2f".format(this)}"
// --- Extension Function برای pipe ---
fun Double.pipe(operation: (Double) -> Double): Double =
operation(this)
val originalPrice = 150.0
// نسخه pipe chain
val finalPricePipe = originalPrice
.pipe(applyDiscount)
.pipe(addTax)
.pipe(roundPrice)
.formatCurrency()
//#################################################################
// فرمت کننده
fun Double.formatCurrency(): String =
"$${"%.2f".format(this)}"
// توابع ساده (غیر-suspending)
val applyDiscount: (Double) -> Double = { price -> price * 0.85 } // 15% off
val addTax: (Double) -> Double = { price -> price * 1.08 } // +8% tax
val roundPrice: (Double) -> Double = { price -> kotlin.math.round(price) }
// نمونهٔ عملیاتِ suspend (مثال: گرفتن نرخ تخفیف داینامیک از شبکه)
val applyDiscountFromNetwork: suspend (Double) -> Double = { price ->
// فرض: call network -> get dynamic discount
// برای مثال ساده، فقط همان 15%:
price * 0.85
}
/**
* Compose a sequence of suspend operations and apply them sequentially to each emitted value.
* Because Flow's map lambda is suspend, we can call suspend ops inside it.
*/
fun <T> Flow<T>.compose(vararg ops: suspend (T) -> T): Flow<T> =
map { value ->
var result = value
for (op in ops) {
result = op(result)
}
result
}
class PriceViewModel : ViewModel() {
private val _originalPrice = MutableStateFlow(150.0) // ورودی قابل تغییر
//val originalPrice: StateFlow<Double> = _originalPrice.asStateFlow()
// pipeline: اعمال تخفیف، اضافه کردن مالیات، رند کردن، سپس فرمت
val finalPriceFlow: StateFlow<String> = _originalPrice
.compose(applyDiscountFromNetwork, addTax, roundPrice) // compose از بالا
.map { it.formatCurrency() } // تبدیل به رشته
.flowOn(Dispatchers.Default) // محاسبات را در پس‌زمینه انجام بده
.stateIn(viewModelScope, SharingStarted.Eagerly, "$0.00")
fun setPrice(p: Double) {
_originalPrice.value = p
}
}
@Composable
fun PriceScreen(viewModel: PriceViewModel = viewModel()) {
val finalPrice by viewModel.finalPriceFlow.collectAsState()
Column(modifier = Modifier.padding(16.dp)) {
Text(text = "Final Price: $finalPrice", style = MaterialTheme.typography.headlineSmall)
// مثلاً دکمه برای تغییر قیمت
Button(onClick = { viewModel.setPrice(200.0) }) {
Text("Set price = 200")
}
}
}
//#################################################################
val addTax: (Double) -> Double = { it * 1.08 }
val roundPrice: (Double) -> Double = { kotlin.math.round(it) }
val discountFromApi: suspend (Double) -> Double = { price ->
// simulate network delay
delay(100)
price * 0.85
}
val pricePipeline = suspendPipeline(discountFromApi, addTax, roundPrice)
viewModelScope.launch {
val result = pricePipeline(150.0)
println(result) // خروجی نهایی بعد از تخفیف، مالیات، رند کردن
}
//#################################################################
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
// نوع داده‌ی مرحله (operation) که dispatcher مخصوص خودش رو هم می‌تونه داشته باشه
data class Stage<T>(
val dispatcher: CoroutineContext,
val op: suspend (T) -> T
)
// سازنده Pipeline
fun <T> suspendPipeline(vararg stages: Stage<T>): suspend (T) -> T = { input ->
var result = input
for (stage in stages) {
withContext(stage.dispatcher) {
result = stage.op(result)
}
}
result
}
// نسخه کمکی برای Stage ساختن راحت‌تر
fun <T> ioStage(op: suspend (T) -> T) = Stage(Dispatchers.IO, op)
fun <T> cpuStage(op: suspend (T) -> T) = Stage(Dispatchers.Default, op)
fun <T> mainStage(op: suspend (T) -> T) = Stage(Dispatchers.Main, op)
val discountFromApi: suspend (Double) -> Double = { price ->
delay(100) // simulate network
price * 0.85
}
val addTax: (Double) -> Double = { it * 1.08 }
val formatCurrency: (Double) -> String = { "$${"%.2f".format(it)}" }
val pricePipeline = suspendPipeline(
ioStage(discountFromApi),
cpuStage { addTax(it) },
mainStage { println("Price: ${formatCurrency(it)}"); it }
)
viewModelScope.launch {
pricePipeline(200.0) // اجرا به ترتیب و روی Dispatcher مناسب
}
//#################################################################
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.coroutines.CoroutineContext
// داده‌ی مرحله که Dispatcher هم داره
data class Stage<T>(
val dispatcher: CoroutineContext,
val op: suspend (T) -> T
)
// کمکی‌ها برای Stage‌سازی راحت
fun <T> ioStage(op: suspend (T) -> T) = Stage(Dispatchers.IO, op)
fun <T> cpuStage(op: suspend (T) -> T) = Stage(Dispatchers.Default, op)
fun <T> mainStage(op: suspend (T) -> T) = Stage(Dispatchers.Main, op)
// نسخه Flow-based
fun <T> Flow<T>.suspendPipelineFlow(vararg stages: Stage<T>): Flow<T> {
return this.map { initial ->
var result = initial
for (stage in stages) {
withContext(stage.dispatcher) {
result = stage.op(result)
}
}
result
}
}
val discountFromApi: suspend (Double) -> Double = { price ->
delay(200) // simulate API
price * 0.85
}
val addTax: (Double) -> Double = { it * 1.08 }
val formatCurrency: (Double) -> String = { "$${"%.2f".format(it)}" }
class PriceViewModel : ViewModel() {
private val _originalPrice = MutableStateFlow(200.0)
val finalPriceFlow: StateFlow<String> = _originalPrice
.suspendPipelineFlow(
ioStage(discountFromApi),
cpuStage { addTax(it) },
mainStage { println("UI logging: $it"); it }
)
.map { formatCurrency(it) }
.stateIn(viewModelScope, SharingStarted.Lazily, formatCurrency(200.0))
fun updatePrice(newPrice: Double) {
_originalPrice.value = newPrice
}
}
@Composable
fun PriceScreen(viewModel: PriceViewModel = viewModel()) {
val finalPrice by viewModel.finalPriceFlow.collectAsState()
Column {
Text("Final Price: $finalPrice")
Button(onClick = { viewModel.updatePrice((100..500).random().toDouble()) }) {
Text("Random Price")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment