How to update a Data attribute defined with Maybe - haskell

I'm playing with Haskell using https://hackage.haskell.org/package/cursor library. I have this data definition:
data TuidoState =
TuidoState { tuidoStateEntries :: Maybe (NonEmptyCursor Entry) }
And I have this function:
buildNewItem :: TuidoState -> TuidoState
buildNewItem s =
let nextID = 10 -- TODO update here to function to return ID
headerTitle = "Test new item"
newEntry = Entry { entryHeader= Header { headerTitle= headerTitle }
, entryBody= Just (Body { bodyTitle= headerTitle })
, entryTags= [Tag {tagName= headerTitle}]
}
actualEntries = (tuidoStateEntries s)
ne = NE.nonEmpty [newEntry]
in
case actualEntries of
Nothing ->
s { tuidoStateEntries = Just(makeNonEmptyCursor ne) }
Just value -> s { tuidoStateEntries = Just(value) } -- possible here I will want to just add the new Entry to the existing list
But, I cannot understand the error:
• Couldn't match expected type ‘NE.NonEmpty Entry’
with actual type ‘Maybe (NE.NonEmpty Entry)’
• In the first argument of ‘makeNonEmptyCursor’, namely ‘ne’
In the first argument of ‘Just’, namely ‘(makeNonEmptyCursor ne)’
In the ‘tuidoStateEntries’ field of a record
|
327 | s { tuidoStateEntries = Just(makeNonEmptyCursor ne) }
Could someone help me with it?

nonEmpty takes an arbitrary list, and so cannot guarantee it returns a non-empty list. Instead, it returns a Maybe (NonEmpty a) to indicate that it may either return a nonempty list or cause an error.
Consider using NonEmpty's constructor, (:|), directly instead.
ne = newEntry NE.:| []

Related

Kotlin getString() exepects an Int? Why?

I'm going through https://developer.android.com/codelabs/basic-android-kotlin-training-project-lemonade. Here, while trying to make "else" do nothing, I've stumbled upon "Type mismatch" errors.
Regarding setting the view elements, this is what I've come up with so far:
private fun setViewElements() {
val textAction: TextView = findViewById(R.id.text_action)
val text = when (lemonadeState) {
SELECT -> R.string.lemon_select
SQUEEZE -> R.string.lemon_squeeze
DRINK -> R.string.lemon_drink
RESTART -> R.string.lemon_empty_glass
else -> null
}
textAction.text = getString(text)
I've tried all workarounds for "doing nothing": {}, Unit, null, empty string (and even data types like String, Int, Double...) but all I get is a "Type mismatch: inferred type is Any but Int was expected" (or "...inferred type is Int?...") error. So much so that an Int does makes the error disapear, as in:
...
else -> 0
According to the docs, both versions of getString(), single and double paramater, work stritcly with strings: parameter(s) and return type. So why on Earth is it saying this function expects an Int?
Also, writing text as an instance of Int (text: Int), doesn't affect anything, meaning it is in fact an Int. I am missing something big here: aren't those R.string.<name> supposed to be strings?
Btw, I did try this:
private fun setViewElements() {
val textAction: TextView = findViewById(R.id.text_action)
val text = when (lemonadeState) {
SELECT -> R.string.lemon_select
SQUEEZE -> R.string.lemon_squeeze
DRINK -> R.string.lemon_drink
else -> R.string.lemon_empty_glass
}
textAction.text = getString(text)
which is errorless and looks better. However, I wanted to keep the specificity, if possible (and it doesn't answer my question).
As the comments pointed out, getString takes a Int, which is a resource ID. This identifies one of the strings you have written in your XML files. This way, you can easily have e.g. multiple versions of the string, one for each localisation for your app, and getString will figure out which string to use based on the device locale. R.string.lemon_select, R.string.lemon_squeeze etc are those identifiers.
One way to do nothing, is to return just evaluate to null - you just have to handle the null value yourself. This will cause text to be of type Int?.
val text = when (lemonadeState) {
SELECT -> R.string.lemon_select
SQUEEZE -> R.string.lemon_squeeze
DRINK -> R.string.lemon_drink
RESTART -> R.string.lemon_empty_glass
else -> null
}
if (text != null) {
textAction.text = getString(text)
}
From your last code snippet though, it seems like you want to set it to lemon_empty_glass when the else branch is reached. If that is the case, then you can do:
val text = when (lemonadeState) {
SELECT -> R.string.lemon_select
SQUEEZE -> R.string.lemon_squeeze
DRINK -> R.string.lemon_drink
RESTART -> R.string.lemon_empty_glass
else -> null
}
textAction.text = getString(text ?: R.string.lemon_empty_glass)

Is it possible to provide a setter function in my computational expression?

I'm trying to write an F# computational expression that permits reading and writing thread-safe variables only from within a critical section.
I've got a type, ThreadSafeVar<'t> that wraps a value, a CriticalSection<'t> and a computational expression builder, LockContext, as follows:
// wraps a value and restricts access to it
type ThreadSafeVar<'t> (value: 't) =
member val internal Value = value with get, set
// Encapsulates a critical section
type CriticalSection<'t> =
private
{ LockObj: obj
fn: unit -> 't }
static member Lock(lc: CriticalSection<'t>) = lock lc.LockObj lc.fn
// Expression builder for a locked context
type LockContext () =
member internal this.SyncRoot = obj()
member this.Return(value: 'v) = value
member this.ReturnFrom(value: ThreadSafeVar<'t>) = value.Value
member __.Bind(value: ThreadSafeVar<'t>, fn: 't -> 'u) = fn value.Value
// returns a CriticalSection
member this.Run(fn : unit -> 'u) = { LockObj = this.SyncRoot
fn=fn }
.
.
.
Reading the thread-safe values from within a lock context is simple enough thanks to Bind. e.g.
let lockedInt = ThreadSafeVar(1) // create a thread-safe variable
let context = LockContext()
let wrapperVal = context {
let! i = lockedInt // get the wrapper value inside lockedInt
return i
} |> CriticalSection.Lock
But I'm struggling to understand how to implement a means setting the value from within a LockContext instance. The approach I've thus taken is to implement a custom operation called, for instance, setVal. I've included my attempts thus far but I'm afraid they'd just muddy the waters. It seems that custom operations operate upon the computation built so far within the expression, encoded as a tuple, but I don't see that this is required in my case.
Any hints, pointing to resources, or direct help would be appreciated.
I'm not at all sure of the wisdom of this, but I came up with something based on the State monad that might work for you. First, define a "stateful" function as one that takes a ThreadSafeVar and returns some type of result:
ThreadSafeVar<'state> -> 'result
We then put that signature into a type that represents a stateful computation:
type Stateful<'state, 'result> =
MkStateful of (ThreadSafeVar<'state> -> 'result)
Now we need a way to run such a computation safely using a given TSV:
let run (tsv : ThreadSafeVar<_>) (MkStateful f) =
lock tsv (fun () -> f tsv)
Note that I've gotten rid of your CriticalSection type and instead just lock the TSV itself.
Next, we need a way to lift a pure value into a stateful computation:
let lift value =
MkStateful (fun _ -> value)
And a way to bind two stateful computations together:
let bind binder stateful =
MkStateful (fun tsv ->
run tsv stateful
|> binder
|> run tsv)
Defining the builder is then trivial:
type LockContext () =
member __.Return(value) = lift value
member __.Bind(stateful, binder) = bind binder stateful
let context = LockContext()
We also need helper computations for setting and getting a value safely:
let getValue =
MkStateful (fun tsv ->
tsv.Value)
let setValue value =
MkStateful (fun tsv ->
tsv.Value <- value)
Putting it all together, we can define a computation that increments the value of a TSV:
let comp =
context {
let! oldValue = getValue
let newValue = oldValue + 1
do! setValue newValue
return newValue
}
And we can run it like this:
let lockedInt = ThreadSafeVar(1)
let result = comp |> run lockedInt
printfn "%A" result // output is: 2
You can see the full solution and try it yourself here.

Nested comprehension in Kotlin

Suppose I have the following nested for loop:
val test = mutableSetOf<Set<Int>>()
for (a in setA) {
for (b in setB) {
if (a.toString().slice(2..3) == b.toString().slice(0..1)) {
test.add(setOf(a,b))
}
}
}
In python, I could do a simple comprehension as
test = {[a,b] for a in setA for b in setB if a.str()[2:3] == b.str[0:1]}
I'm having a helluva time converting this to Kotlin syntax. I know for a single for loop with a conditional, I could use a filter and map to get the desired results (using the idiom: newSet = oldSet.filter{ conditional }.map { it }, but I cannot for the life of me figure out how to do the nesting this way.
This is what IDEA proposes:
for (a in setA)
setB
.filter { a.toString().slice(2..3) == it.toString().slice(0..1) }
.mapTo(test) { setOf(a, it) }
I do not think there is much to do about it. I think their is no native approach that is similar to the Python one, but it already actually is in terms of length very similar because only the functions and their names make it that long.
If we take a look a this hypothetical example:
for (a in setA) setB.f { a.t().s(2..3) == it.t().s(0..1) }.m(test) { setOf(a, it) }
It is not far from the Python example. The Python syntax is just very different.
(functions for that hypothesis)
fun <T> Iterable<T>.f(predicate: (T) -> Boolean) = filter(predicate)
fun String.s(range: IntRange) = slice(range)
fun <T, R, C : MutableCollection<in R>> Iterable<T>.m(destination: C, transform: (T) -> R) = mapTo(destination, transform)
fun Int.t() = toString()
If Kotlin doesn't have it, add it. Here is a cartesian product of the two sets as a sequence:
fun <F,S> Collection<F>.cartesian(other: Collection<S>): Sequence<Pair<F,S>> =
this.asSequence().map { f -> other.asSequence().map { s-> f to s } }.flatten()
Then use that in one of many ways:
// close to your original nested loop version:
setA.cartesian(setB).filter { (a,b) ->
a.toString().slice(2..3) == b.toString().slice(0..1)
}.forEach{ (a,b) -> test.add(setOf(a,b)) }
// or, add the pair instead of a set if that makes sense as alternative
setA.cartesian(setB).filter { (a,b) ->
a.toString().slice(2..3) == b.toString().slice(0..1)
}.forEach{ test2.add(it) }
// or, add the results of the full expression to the set at once
test.addAll(setA.cartesian(setB).filter { (a,b) ->
a.toString().slice(2..3) == b.toString().slice(0..1)
}.map { (a,b) -> setOf(a,b) } )
// or, the same as the last using a pair instead of 2 member set
test2.addAll(setA.cartesian(setB).filter { (a,b) ->
a.toString().slice(2..3) == b.toString().slice(0..1)
})
The above examples use these variables:
val test = mutableSetOf<Set<Int>>()
val test2 = mutableSetOf<Pair<Int,Int>>()
val setA = setOf<Int>()
val setB = setOf<Int>()

Optimization of F# string manipulation

I am just learning F# and have been converting a library of C# extension methods to F#. I am currently working on implementing a function called ConvertFirstLetterToUppercase based on the C# implementation below:
public static string ConvertFirstLetterToUppercase(this string value) {
if (string.IsNullOrEmpty(value)) return value;
if (value.Length == 1) return value.ToUpper();
return value.Substring(0, 1).ToUpper() + value.Substring(1);
}
The F# implementation
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module public StringHelper
open System
open System.Collections.Generic
open System.Linq
let ConvertHelper (x : char[]) =
match x with
| [| |] | null -> ""
| [| head; |] -> Char.ToUpper(head).ToString()
| [| head; _ |] -> Char.ToUpper(head).ToString() + string(x.Skip(1).ToArray())
[<System.Runtime.CompilerServices.ExtensionAttribute>]
let ConvertFirstLetterToUppercase (_this : string) =
match _this with
| "" | null -> _this
| _ -> ConvertHelper (_this.ToCharArray())
Can someone show me a more concise implementation utilizing more natural F# syntax?
open System
type System.String with
member this.ConvertFirstLetterToUpperCase() =
match this with
| null -> null
| "" -> ""
| s -> s.[0..0].ToUpper() + s.[1..]
Usage:
> "juliet".ConvertFirstLetterToUpperCase();;
val it : string = "Juliet"
Something like this?
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module public StringHelper =
[<System.Runtime.CompilerServices.ExtensionAttribute>]
let ConvertFirstLetterToUppercase (t : string) =
match t.ToCharArray() with
| null -> t
| [||] -> t
| x -> x.[0] <- Char.ToUpper(x.[0]); System.String(x)
Try the following
[<System.Runtime.CompilerServices.ExtensionAttribute>]
module StringExtensions =
let ConvertFirstLetterToUpperCase (data:string) =
match Seq.tryFind (fun _ -> true) data with
| None -> data
| Some(c) -> System.Char.ToUpper(c).ToString() + data.Substring(1)
The tryFind function will return the first element for which the lambda returns true. Since it always returns true it will simply return the first element or None. Once you've established there is at least one element you know data is not null and hence can call Substring
There's nothing wrong with using .NET library functions from a .NET language. Maybe a direct translation of your C# extension method is most appropriate, particularly for such a simple function. Although I'd be tempted to use the slicing syntax like Juliet does, just because it's cool.
open System
open System.Runtime.CompilerServices
[<Extension>]
module public StringHelper =
[<Extension>]
let ConvertFirstLetterToUpperCase(this:string) =
if String.IsNullOrEmpty this then this
elif this.Length = 1 then this.ToUpper()
else this.[0..0].ToUpper() + this.[1..]

optional arguments in haskell

I have declared my own type:
data Book = Bookinfo {
bookId :: Int,
title :: String
} deriving(Show)
and now:
x = Bookinfo
it is all ok, valid statement
but making bookId x throws an error.
If I would be able to handle errors in Haskell that would be ok but right now I cant do this So Im curious how to make not specified values of fields take default value, and what exactly value is there when I'm not giving vcalues of fields in construcotr ?
thanks for help
-- this one is not a Book but actually a function that can make one:
alternativeCtrFunc = Bookinfo
defaultBook = Bookinfo { bookId = 3, title = "Welcome to the Monkey House" }
x = defaultBook
y = defaultBook { bookId = 7 }
z = defaultBook { title = "The Cider House Rules" }

Resources