Node.js effects in Thermite for Electron - reactjs
I am trying to expand https://github.com/kRITZCREEK/electron-apps-with-purescript to add an input for the directory whose filenames I would display.
However, I cannot get the following function to typecheck (the last two lines are problematic, the last is line 53):
performAction :: T.PerformAction _ State _ Action
performAction (SetEditText s) _ _ = void do
T.cotransform $ _ { dir = s }
performAction (UpdateFiles s) _ _ = void do
filenames <- either (const []) id <$> try (readdir s)
T.cotransform $ _ { names = filenames }
Here readdir is from Node.FS.Sync and has the signature
forall eff. String -> Eff (fs :: FS, err :: EXCEPTION | eff) (Array String)
and performAction is of type
forall t39 t40. Action -> t40 -> {dir :: String, names :: Array String} -> FreeT (CoTransform (Maybe {dir :: String, names :: Array String}) ({dir :: String, names :: Array String} -> {dir :: String, names :: Array String}))
The actual error is
Could not match type at line 53 col 4
FreeT
(CoTransform t2
({ files :: t3
| t4
}
-> { files :: Array String
| t4
}
)
)
with type
Eff
while trying to match type FreeT
(CoTransform t2
({ files :: t3
| t4
}
-> { files :: Array String
| t4
}
)
)
t5
with type Eff
( fs :: FS
| t0
)
while checking that expression (apply cotransform) (\$1 ->
$1 { files = f
}
)
has type Eff
( fs :: FS
| t0
)
t1
in value declaration performAction
where t1 is an unknown type
t0 is an unknown type
t2 is an unknown type
t5 is an unknown type
t4 is an unknown type
t3 is an unknown type
(The whole project can be found under https://github.com/MarkusBarthlen/electron-apps-with-purescript/blob/master/src/Main.purs)
I suspect I have to use any of lift/liftEff/liftEff'/liftAff. However,
performAction :: T.PerformAction _ State _ Action
performAction (UpdateFiles s) _ _ = void do
filenames <- ( lift (either (const []) id <$> try (readdir s)))
T.cotransform $ _ { names = filenames }
results in
Could not match type at line 55 col 47
Eff
with type
Aff
while trying to match type Eff
( fs :: FS
| t1
)
with type Aff t0
You can make it work with:
performAction :: forall e. T.PerformAction (fs :: FS | e) State _ Action
performAction (SetEditText s) _ _ = void do
T.cotransform $ _ { dir = s }
performAction (UpdateFiles s) _ _ = void do
filenames <- lift (liftEff (either (const []) id <$> try (readdir s)))
T.cotransform $ _ { names = filenames }
-- T.cotransform $ _ { dir = ""}
liftEff takes your Eff to an Aff and lift then raises that into the FreeT ... that Thermite uses. The extra lift shouldn't be necessary, but I think the problem is type inference around rows and typeclasses here and the situation should get better with the next release where we'll most likely have functional dependencies.
Related
Scala: Parsing Array of String to a case class
I have created a case class like this: def case_class(): Unit = { case class StockPrice(quarter : Byte, stock : String, date : String, open : Double, high : Double, low : Double, close : Double, volume : Double, percent_change_price : Double, percent_change_volume_over_last_wk : Double, previous_weeks_volume : Double, next_weeks_open : Double, next_weeks_close : Double, percent_change_next_weeks_price : Double, days_to_next_dividend : Double, percent_return_next_dividend : Double ) And I have thousands of line as Array of String like this: 1,AA,1/7/2011,$15.82,$16.72,$15.78,$16.42,239655616,3.79267,,,$16.71,$15.97,-4.42849,26,0.182704 1,AA,1/14/2011,$16.71,$16.71,$15.64,$15.97,242963398,-4.42849,1.380223028,239655616,$16.19,$15.79,-2.47066,19,0.187852 1,AA,1/21/2011,$16.19,$16.38,$15.60,$15.79,138428495,-2.47066,-43.02495926,242963398,$15.87,$16.13,1.63831,12,0.189994 1,AA,1/28/2011,$15.87,$16.63,$15.82,$16.13,151379173,1.63831,9.355500109,138428495,$16.18,$17.14,5.93325,5,0.185989 How Can I parse data from Array into that case class? Thank you for your help!
You can proceed as below (I've taken simplified example) Given your case class and data (lines) // Your case-class case class MyCaseClass( fieldByte: Byte, fieldString: String, fieldDouble: Double ) // input data val lines: List[String] = List( "1,AA,$1.1", "2,BB,$2.2", "3,CC,$3.3" ) Note: you can read lines from a text file as val lines = Source.fromFile("my_file.txt").getLines.toList You can have some utility methods for mapping (cleaning & parsing) // remove '$' symbols from string def removeDollars(line: String): String = line.replaceAll("\\$", "") // split string into tokens and // convert into MyCaseClass object def parseLine(line: String): MyCaseClass = { val tokens: Seq[String] = line.split(",") MyCaseClass( fieldByte = tokens(0).toByte, fieldString = tokens(1), fieldDouble = tokens(2).toDouble ) } And then use them to convert strings into case-class objects // conversion val myCaseClassObjects: Seq[MyCaseClass] = lines.map(removeDollars).map(parseLine) As a more advanced (and generalized) approach, you can generate the mapping (parsing) function for converting tokens into fields of your case-class using something like reflection, as told here
Here's one way of doing it. I'd recommend splitting everything you do up into lots of small, easy-to-manage functions, otherwise you will get lost trying to figure out where something is going wrong if it all starts throwing exceptions. Data setup: val array = Array("1,AA,1/7/2011,$15.82,$16.72,$15.78,$16.42,239655616,3.79267,,,$16.71,$15.97,-4.42849,26,0.182704", "1,AA,1/14/2011,$16.71,$16.71,$15.64,$15.97,242963398,-4.42849,1.380223028,239655616,$16.19,$15.79,-2.47066,19,0.187852", "1,AA,1/21/2011,$16.19,$16.38,$15.60,$15.79,138428495,-2.47066,-43.02495926,242963398,$15.87,$16.13,1.63831,12,0.189994", "1,AA,1/28/2011,$15.87,$16.63,$15.82,$16.13,151379173,1.63831,9.355500109,138428495,$16.18,$17.14,5.93325,5,0.185989") case class StockPrice(quarter: Byte, stock: String, date: String, open: Double, high: Double, low: Double, close: Double, volume: Double, percent_change_price: Double, percent_change_volume_over_last_wk: Double, previous_weeks_volume: Double, next_weeks_open: Double, next_weeks_close: Double, percent_change_next_weeks_price: Double, days_to_next_dividend: Double, percent_return_next_dividend: Double ) Function to turn Array[String] into Array[List[String]] and handle any empty fields (I've made an assumption here that you want empty fields to be 0. Change this as necessary): def splitArray(arr: Array[String]): Array[List[String]] = { arr.map( _.replaceAll("\\$", "") // Remove $ .split(",") // Split by , .map { case x if x.isEmpty => "0" // If empty case y => y // If not empty } .toList ) } Function to turn a List[String] into a StockPrice. Note that this will fall over if the List isn't exactly 16 items long. I'll leave you to handle any of that. Also, the names are pretty non-descriptive so you can change that too. It will also fall over if your data doesn't map to the relevant .toDouble or toByte or whatever - you can handle this yourself too: def toStockPrice: List[String] => StockPrice = { case a :: b :: c :: d :: e :: f :: g :: h :: i :: j :: k :: l :: m :: n :: o :: p :: Nil => StockPrice(a.toByte, b, c, d.toDouble, e.toDouble, f.toDouble, g.toDouble, h.toDouble, i.toDouble, j.toDouble, k.toDouble, l.toDouble, m.toDouble, n.toDouble, o.toDouble, p.toDouble) } A nice function to bring this all together: def makeCaseClass(arr: Array[String]): Seq[StockPrice] = { val splitArr: Array[List[String]] = splitArray(arr) splitArr.map(toStockPrice) } Output: println(makeCaseClass(array)) //ArraySeq( // StockPrice(1,AA,1/7/2011,15.82,16.72,15.78,16.42,2.39655616E8,3.79267,0.0,0.0,16.71,15.97,-4.42849,26.0,0.182704), // StockPrice(1,AA,1/14/2011,16.71,16.71,15.64,15.97,2.42963398E8,-4.42849,1.380223028,2.39655616E8,16.19,15.79,-2.47066,19.0,0.187852), // StockPrice(1,AA,1/21/2011,16.19,16.38,15.6,15.79,1.38428495E8,-2.47066,-43.02495926,2.42963398E8,15.87,16.13,1.63831,12.0,0.189994), // StockPrice(1,AA,1/28/2011,15.87,16.63,15.82,16.13,1.51379173E8,1.63831,9.355500109,1.38428495E8,16.18,17.14,5.93325,5.0,0.185989) //) Edit: To explain the a :: b :: c ..... bit - this is a way of assigning names to items in a List or Seq, given you know the List's size. val ls = List(1, 2, 3) val a :: b :: c :: Nil = List(1, 2, 3) println(a == ls.head) // true println(b == ls(1)) // true println(c == ls(2)) // true Note that the Nil is important because it signifies the last element of the List being Nil. Without it, c would be equal to List(3) as the rest of any List is assigned to the last value in your definition. You can use this in pattern matching as I have in order to do something with the results: val ls = List(1, "b", true) ls match { case a :: b :: c if c == true => println("this will not be printed") case a :: b :: c :: Nil if c == true => println(s"this will get printed because c == $c") } // not exhaustive but you get the point You can also use it if you know what you want each element in the List to be, like this: val personCharacteristics = List("James", 26, "blue", 6, 85.4, "brown") val name :: age :: eyeColour :: otherCharacteristics = personCharacteristics println(s"Name: $name; Age: $age; Eye colour: $eyeColour") // Name: James; Age: 26; Eye colour: blue Obviously these examples are pretty trivial and not exactly what you'd see as a professional Scala developer (at least I don't), but it's a handy thing to be aware of as I do still use this :: syntax at work sometimes.
Haskell fetchName from X11 library does not return the name of the window
Having the following Haskell code: import Control.Concurrent import Data.Time.Clock import Debug.Trace import Graphics.X11 import Graphics.X11.Xlib.Extras main :: IO () main = do d <- openDisplay "" loop d loop :: Display -> IO () loop d = do time <- getCurrentTime (w, _) <- getInputFocus d maybeName <- fetchName d w windowAttrs <- getWindowAttributes d w print $ show time ++ " Name: " ++ show maybeName ++ " Width: " ++ show (wa_width windowAttrs) threadDelay 1000000 loop d The window title returned by fetchName is always Nothing. Haskell X11 library is a wrapper around Xlib Possibly related issues: The width of the window is either correct or it has the value 1. XFetchName always returns 0
It looks like fetchName isn't always filled in. Instead you need to use the _NET_WM_NAME property: import Control.Concurrent import Data.Time.Clock import Debug.Trace import Graphics.X11 import Graphics.X11.Xlib.Extras main :: IO () main = do d <- openDisplay "" loop d loop :: Display -> IO () loop d = do time <- getCurrentTime (w, _) <- getInputFocus d a <- internAtom d "_NET_WM_NAME" False p <- getTextProperty d w a ps <- wcTextPropertyToTextList d p windowAttrs <- getWindowAttributes d w print $ show time ++ " Name: " ++ show ps ++ " Width: " ++ show (wa_width windowAttrs) threadDelay 1000000 loop d This is what XMonad does: https://github.com/xmonad/xmonad/blob/8b055621e92e7ade127043e968f50713c15a00a0/src/XMonad/ManageHook.hs#L71-L80
In the end I had to adapt Brian's answer to the more complete definition from XMonad (because of exceptions being thrown by some windows): import Control.Exception.Extensible (SomeException (..), bracket) import qualified Control.Exception.Extensible as E import Graphics.X11 import Graphics.X11.Xlib.Extras getWindowTitle :: Display -> IO String getWindowTitle d = do (w, _) <- getInputFocus d let getProp = (internAtom d "_NET_WM_NAME" False >>= getTextProperty d w) `E.catch` \(SomeException _) -> getTextProperty d w wM_NAME extract prop = do l <- wcTextPropertyToTextList d prop return $ if null l then "" else head l bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""
Implementation of Array data type in OCaml
I have very little knowledge about OCaml as a whole and just received an assignment to take one of the source files in the project and allow it to take a new data type (Array). I am not asking for someone to solve this problem for me, but instead I would appreciate someone walking me through this code. I would also appreciate any input on how difficult it is going to be to implement this new data type. The file itself lacks a lot of documentation which doesn't make it any easier either. (* * Types (hashconsed) *) (* ** Imports *) open Abbrevs open Util (* ** Identifiers *) module Lenvar : (module type of Id) = Id module Tysym : (module type of Id) = Id module Groupvar : (module type of Id) = Id module Permvar : (module type of Id) = Id (* ** Types and type nodes *) type ty = { ty_node : ty_node; ty_tag : int } and ty_node = | BS of Lenvar.id | Bool | G of Groupvar.id | TySym of Tysym.id | Fq | Prod of ty list | Int (* ** Equality, hashing, and hash consing *) let equal_ty : ty -> ty -> bool = (==) let hash_ty t = t.ty_tag let compare_ty t1 t2 = t1.ty_tag - t2.ty_tag module Hsty = Hashcons.Make (struct type t = ty let equal t1 t2 = match t1.ty_node, t2.ty_node with | BS lv1, BS lv2 -> Lenvar.equal lv1 lv2 | Bool, Bool -> true | G gv1, G gv2 -> Groupvar.equal gv1 gv2 | TySym ts1, TySym ts2 -> Tysym.equal ts1 ts2 | Fq, Fq -> true | Prod ts1, Prod ts2 -> list_eq_for_all2 equal_ty ts1 ts2 | _ -> false let hash t = match t.ty_node with | BS lv -> hcomb 1 (Lenvar.hash lv) | Bool -> 2 | G gv -> hcomb 3 (Groupvar.hash gv) | TySym gv -> hcomb 4 (Tysym.hash gv) | Fq -> 5 | Prod ts -> hcomb_l hash_ty 6 ts | Int -> 7 let tag n t = { t with ty_tag = n } end) (** Create [Map], [Set], and [Hashtbl] modules for types. *) module Ty = StructMake (struct type t = ty let tag = hash_ty end) module Mty = Ty.M module Sty = Ty.S module Hty = Ty.H (* ** Constructor functions *) let mk_ty n = Hsty.hashcons { ty_node = n; ty_tag = (-1) } let mk_BS lv = mk_ty (BS lv) let mk_G gv = mk_ty (G gv) let mk_TySym ts = mk_ty (TySym ts) let mk_Fq = mk_ty Fq let mk_Bool = mk_ty Bool let mk_Int = mk_ty Int let mk_Prod tys = match tys with | [t] -> t | _ -> mk_ty (Prod tys) (* ** Indicator and destructor functions *) let is_G ty = match ty.ty_node with | G _ -> true | _ -> false let is_Fq ty = match ty.ty_node with | Fq -> true | _ -> false let is_Prod ty = match ty.ty_node with | Prod _ -> true | _ -> false let destr_G_exn ty = match ty.ty_node with | G gv -> gv | _ -> raise Not_found let destr_BS_exn ty = match ty.ty_node with | BS lv -> lv | _ -> raise Not_found let destr_Prod_exn ty = match ty.ty_node with | Prod ts -> ts | _ -> raise Not_found let destr_Prod ty = match ty.ty_node with | Prod ts -> Some ts | _ -> None (* ** Pretty printing *) let pp_group fmt gv = if Groupvar.name gv = "" then F.fprintf fmt "G" else F.fprintf fmt "G_%s" (Groupvar.name gv) let rec pp_ty fmt ty = match ty.ty_node with | BS lv -> F.fprintf fmt "BS_%s" (Lenvar.name lv) | Bool -> F.fprintf fmt "Bool" | Fq -> F.fprintf fmt "Fq" | TySym ts -> F.fprintf fmt "%s" (Tysym.name ts) | Prod ts -> F.fprintf fmt "(%a)" (pp_list " * " pp_ty) ts | Int -> F.fprintf fmt "Int" | G gv -> if Groupvar.name gv = "" then F.fprintf fmt "G" else F.fprintf fmt "G_%s" (Groupvar.name gv)
It's hard to walk through this code because quite a bit is missing (definitions of Id, Hashcons, StructMake). But in general this code manipulates data structures that represent types. You can read about hash consing here: https://en.wikipedia.org/wiki/Hash_consing (which is what I just did myself). In essence it is a way of maintaining a canonical representation for a set of structures (in this case, structures representing types) so that two structures that are equal (having constituents that are equal) are represented by the identical value. This allows constant-time comparison for equality. When you do this with strings, it's called "interning" (a technique from Lisp I've used many times). To add arrays, you need to know whether the array type will include the length of the array or just the type of its elements. The semi-mysterious type BS seems to include a length, which suggests you may want to include the length in your reprsentation. If I were doing this project I would look for every occurence of Prod (which represents tuples) and I'd add a type representing Array in an analogous way. Instead of a list of constituent types (as for a tuple) you have one constituent type and (I would guess) a variable representing the length of the array. Before starting out I'd look for some documentation, on what BS represents for one thing. I also have no idea what "groups" are, but maybe you could worry about it later. Update Here's what I mean by copying Prod. Keep in mind that I am basing this almost entirely on guesswork. So, many details (or even the entire idea) could be wrong. The current definition of a type looks like this: and ty_node = | BS of Lenvar.id | Bool | G of Groupvar.id | TySym of Tysym.id | Fq | Prod of ty list | Int If you add a representation for Array after Prod you get something like this: and ty_node = | BS of Lenvar.id | Bool | G of Groupvar.id | TySym of Tysym.id | Fq | Prod of ty list | Array of Lenvar.id * ty | Int You would then go through the rest of the code adding support for the new Array variant. The compiler will help you find many of the places that need fixing.
(Dependantly?) typing containers
Given a type constructor/container F[_] I want to make a combinator which can compose polymorphic types and hlist types into a new container by the following ruleset: F[HNil] and F[HNil] into a F[HNil] F[A] and F[HNil] into a F[A :: HNil] F[HNil] and F[A] into a F[A :: HNil] F[A] and F[B] into a F[A :: B :: HNil] F[L <: HList] and F[R <: HList] into a F[L :: R] (hlist concat) F[A] and F[R <: HList] into a F[A :: R] (hlist prepend) F[L <: HList] and F[B] into a F[L :: B :: HNil] (hlist append) Is there a nice way to do this in shapeless? Or is there a easier way to solve this particular problem :) The thing is that I have combinators which yield a F[Int], F[HNil] and F[HNil]. Combining these should not yield a F[Int :: HNil :: HNil] (but F[Int :: HNil]) for example. For this purpose now I've made typeclass: trait CodecAppender[F, A, B] { type Out final type CodecOut = Codec[F, Out] def apply(a: Codec[F, A], b: Codec[F, B]): CodecOut } object CodecAppender { type Aux[F, A, B, C] = CodecAppender[F, A, B] { type Out = C } private def make[F, A, B, C](decompose: C => (A, B))(implicit S: Monoid[F], D: DecoderAppender.Aux[F, A, B, C]): Aux[F, A, B, C] = new CodecAppender[F, A, B] { type Out = C def apply(a: Codec[F, A], b: Codec[F, B]): CodecOut = new Codec[F, C] { def encode(in: C) = { val (head, tail) = decompose(in) a.encode(head) |+| b.encode(tail) } val decoder = D.append(a.decoder, b.decoder) } } implicit def HNilAndHNil[F, O](implicit M: Monoid[F], D: DecoderAppender.Aux[F, HNil, HNil, HNil]) = make[F, HNil, HNil, HNil](r => HNil -> HNil) //other cases omitted, but there are 6 more (which I described above) }
There is a nice way of doing just that using a series of type classes. You can do something if your F[_] has an instance of an Monad: trait Conv[A]{ type Out <: HList def apply(a: A): Out } object Conv extends LowPrior{ implicit def hlist[L <: HList] = new Conv[L]{ type Out = L def apply(hl: L) = hl } } trait LowPrior{ implicit def other[A] = new Conv[A]{ type Out = H :: HNil def apply(a: A) = a :: HNil } } def combineF[F[_], A, B](fa: F[A], fb: F[B])(implicit ca: Conv[A], cb: Conv[B], m: Monad[F]) = m.flatMap(fa){ a: A => m.map(fb){ b: B => ca(a) ::: c(b) } } If you want the real return types you could define an Aux type in Conv companion object and then use the Prepend type class of an HList to get the final realized result type. (I'm actually fairly positive you could achieve the same thing with an Applicative or even a Zip type class. Will leave that up to you to discover.)
Scodec is doing something like that : def prepend[A, L <: HList](a: Codec[A], l: Codec[L]): Codec[A :: L] = new Codec[A :: L] { override def sizeBound = a.sizeBound + l.sizeBound override def encode(xs: A :: L) = Codec.encodeBoth(a, l)(xs.head, xs.tail) override def decode(buffer: BitVector) = Codec.decodeBothCombine(a, l)(buffer) { _ :: _ } override def toString = s"$a :: $l" } https://github.com/scodec/scodec/blob/ac71016dcea61cc6aaabe4f4dff4ab5bf13ac239/shared/src/main/scala/scodec/codecs/HListCodec.scala#L19-L25
ML can't unify 'a with int
The exercise is to code a function in ML that deletes an element from a binary search tree. Here's the code: datatype 'a tree = Lf | Br of 'a * 'a tree * 'a tree; fun deleteTop (Br(_, Lf, t2)) = t2 | deleteTop (Br(_, t1, Lf)) = t1 | deleteTop (Br(_, Br(v, u1, u2), t2)) = Br(v, deleteTop (Br(v, u1, u2)), t2); fun delete (Lf, k : string) = Lf | delete (Br((a,b),t1,t2), k) = if a=k then deleteTop(Br((a,b),t1,t2)) else if k<a then Br((a,b),delete(t1,k),t2) else Br((a,b),t1,delete(t2,k)); When I load this into Poly/ML it warns me of incomplete pattern matching in deleteTop but that doesn't matter because delete only ever passes deleteTop a branch. val deleteTop = fn: 'a tree -> 'a tree val delete = fn: (string * 'a) tree * string -> (string * 'a) tree I created a (string * int) tree and ran > delete(a,"they"); Error-Type error in function application. Function: delete : (string * 'a) tree * string -> (string * 'a) tree Argument: (a, "they") : (string * int) tree * string Reason: Can't unify (string * 'a) tree with (string * int) tree (Different type constructors) Found near delete (a, "they") Static Errors Let me re-iterate one of those lines: Can't unify (string * 'a) tree with (string * int) tree Why can't ML unify 'a with int?
You can get a message like that if you have redefined tree and delete at the top level since you defined a. It's complaining that the tree in a is not the same as the tree in delete. For example > datatype 'a t = T of 'a; datatype 'a t = T of 'a > val x = T 1; val x = T 1: int t > datatype 'a t = T of 'a; datatype 'a t = T of 'a > val T y = x; Pattern and expression have incompatible types. Pattern: T y : 'a t Expression: x : int t Reason: Can't unify 'a t with int t (Different type constructors) Found near val T y = x Static Errors >