diff --git a/docs/samples/сумма_ряда.lyng.md b/docs/samples/сумма_ряда.lyng.md new file mode 100644 index 0000000..ca6f860 --- /dev/null +++ b/docs/samples/сумма_ряда.lyng.md @@ -0,0 +1,37 @@ +# Пример расчета суммы ряда + +Рассмотрим как можно посчитать предел суммы ряда на lyng. Для наивной реализации +представим что у нас есть функция рассчитывающая n-й член ряда. Тогда мы можем +считать сумму до тех пор, пока отклонение при расчете следующего члена не станет +меньше чем заданная погрешность: + + fun сумма_ряда(x, погрешность=0.0001, f) { + var сумма = 0 + for( n in 1..100000) { + val следующая_сумма = сумма + f(x, n) + if( n > 1 && abs(следующая_сумма - сумма) < погрешность ) + break следующая_сумма + сумма = следующая_сумма + } + else null + } + +Для проверки можно посчитать на хорошо известном ряду Меркатора + +$$ \ln(1+x)=x-{\dfrac {x^{2}}{2}}+{\dfrac {x^{3}}{3}}-\cdots =\sum \limits _{n=0}^{\infty }{\dfrac {(-1)^{n}x^{n+1}}{(n+1)}}=\sum \limits _{n=1}^{\infty }{\dfrac {(-1)^{n-1}x^{n}}{n}} +$$ + +Который в нашем случае для точки $x = 1$ можно записать так: + + val x = сумма_ряда(1) { x, n -> + val sign = if( n % 2 == 1 ) 1 else -1 + sign * pow(x, n) / n + } + +Проверим: + + assert( x - ln(2) < 0.001 ) + +Во многих случаях вычисление $n+1$ члена значительно проще cчитается от предыдущего члена, в нашем случае это можно было бы записать через итератор, что мы вскоре добавим. + +(продолжение следует) diff --git a/docs/tutorial.md b/docs/tutorial.md index 6da0ad1..0114da3 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -15,8 +15,7 @@ __Other documents to read__ maybe after this one: - [OOP notes](OOP.md) - [math in Lyng](math.md) - Some class references: [List], [Real], [Range], [Iterable], [Iterator] -- Some samples: [combinatorics](samples/combinatorics.lyng.md) - See [samples folder](samples) +- Some samples: [combinatorics](samples/combinatorics.lyng.md), national vars and loops: [сумма ряда](samples/сумма_ряда.lyng.md). More at [samples folder](samples) # Expressions diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt index bb72d99..a0aa1da 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/ArgsDeclaration.kt @@ -53,7 +53,11 @@ data class ArgsDeclaration(val params: List, val endTokenType: Token.Type) val value = when { i < callArgs.size -> callArgs[i] a.defaultValue != null -> a.defaultValue.execute(context) - else -> context.raiseArgumentError("too few arguments for the call") + else -> { + println("callArgs: ${callArgs.joinToString()}") + println("tailBlockMode: ${arguments.tailBlockMode}") + context.raiseArgumentError("too few arguments for the call") + } } assign(a, value) i++ diff --git a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index 116ef24..059b120 100644 --- a/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/library/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -140,7 +140,7 @@ class Compiler( Token.Type.LPAREN -> { cc.next() // instance method call - val args = parseArgs(cc) + val args = parseArgs(cc).first isCall = true operand = Accessor { context -> context.pos = next.pos @@ -552,7 +552,11 @@ class Compiler( return result } - private fun parseArgs(cc: CompilerContext): List { + /** + * Parse arguments list during the call and detect last block argument + * _following the parenthesis_ call: `(1,2) { ... }` + */ + private fun parseArgs(cc: CompilerContext): Pair, Boolean> { val args = mutableListOf() do { @@ -578,6 +582,7 @@ class Compiler( // block after? val pos = cc.savePos() val end = cc.next() + var lastBlockArgument = false if (end.type == Token.Type.LBRACE) { // last argument - callable val callableAccessor = parseLambdaExpression(cc) @@ -588,14 +593,16 @@ class Compiler( }, end.pos ) + lastBlockArgument = true } else cc.restorePos(pos) - return args + return args to lastBlockArgument } private fun parseFunctionCall(cc: CompilerContext, left: Accessor, blockArgument: Boolean): Accessor { // insofar, functions always return lvalue + var detectedBlockArgument = blockArgument val args = if (blockArgument) { val blockArg = ParsedArgument( parseExpression(cc) @@ -603,7 +610,9 @@ class Compiler( ) listOf(blockArg) } else { - parseArgs(cc) + val r = parseArgs(cc) + detectedBlockArgument = r.second + r.first } return Accessor { context -> @@ -611,7 +620,7 @@ class Compiler( v.value.callOn( context.copy( context.pos, - args.toArguments(context, blockArgument) + args.toArguments(context, detectedBlockArgument) // Arguments( // args.map { Arguments.Info((it.value as Statement).execute(context), it.pos) } // ), diff --git a/library/src/commonTest/kotlin/ScriptTest.kt b/library/src/commonTest/kotlin/ScriptTest.kt index 95b2089..9f851cd 100644 --- a/library/src/commonTest/kotlin/ScriptTest.kt +++ b/library/src/commonTest/kotlin/ScriptTest.kt @@ -1640,4 +1640,49 @@ class ScriptTest { """.trimIndent()) } + + @Test + fun nationalCharsTest() = runTest { + eval(""" + fun сумма_ряда(x, погрешность=0.0001, f) { + var сумма = 0 + for( n in 1..100000) { + val следующая_сумма = сумма + f(x, n) + if( n > 1 && abs(следующая_сумма - сумма) < погрешность ) + break следующая_сумма + сумма = следующая_сумма + } + else null + } + val x = сумма_ряда(1) { x, n -> + val sign = if( n % 2 == 1 ) 1 else -1 + sign * pow(x, n) / n + } + assert( x - ln(2) < 0.001 ) + """.trimIndent()) + } +// +// @Test +// fun customIteratorTest() = runTest { +// eval(""" +// fun сумма_ряда2(погрешность=0.0001, iterator) { +// var сумма = 0 +// for( n in 1..100000) { +// if( !iterator.hasNext() ) break сумма +// val следующая_сумма = сумма + iterator.next() +// if( n > 1 && abs(следующая_сумма - сумма) < погрешность ) +// break следующая_сумма +// сумма = следующая_сумма +// } +// else null +// } +// val +// val x = сумма_ряда2(1) { x, n -> +// val sign = if( n % 2 == 1 ) 1 else -1 +// sign * pow(x, n) / n +// } +// assert( x - ln(2) < 0.001 ) +// """.trimIndent()) +// } + } \ No newline at end of file