Digging through the source:
https://github.com/slamdata/purescript-affjax/blob/v5.0.0/src/Network/HTTP/Affjax.purs#L92
stumbled upon the signature of get:
get :: forall e a. Respondable a => URL -> Affjax e a
and ventured into psci:
> import Network.HTTP.Affjax
> :t get
forall e a.
Respondable a => String
-> Aff
( ajax :: AJAX
| e
)
{ status :: StatusCode
, headers :: Array ResponseHeader
, response :: a
}
Focusing on the tail part of return type, how is:
Respondable a =>
{ status :: StatusCode
, headers :: Array ResponseHeader
, response :: a
}
matched against Respondable a from the first signature -- a from Respondable a => Affjax e a? Zilch of the instances of Respondable:
instance responsableBlob :: Respondable Blob where
instance responsableDocument :: Respondable Document where
instance responsableForeign :: Respondable Foreign where
instance responsableString :: Respondable String where
instance responsableUnit :: Respondable Unit where
instance responsableArrayBuffer :: Respondable A.ArrayBuffer where
instance responsableJson :: Respondable Json where
matche Record. Waat's going on?!
Elucidate the lone rabbit how to dig herself out of similar deep holes in the future. Tnx!
I'm not sure if I fully understand your question but I think that your problem rised from the fact that psci expands type aliases.
Let's try to do this manually and check if it has done good job. You can find these type aliases in the same file where get is defined:
type Affjax e a =
Aff
(ajax :: AJAX | e)
(AffjaxResponse a)
type AffjaxResponse a =
{ status :: StatusCode
, headers :: Array ResponseHeader
, response :: a
}
So given that get has type:
get :: forall e a
. Respondable a
=> URL
-> Affjax e a
we can try to substitute all it's aliases. I'm using vertical formatting here for readability. Let's use first alias for Affjax a e:
-- using first alias
get :: forall e a
. Respondable a
=> URL
-> Aff
(ajax :: AJAX | e)
(AffjaxResponse a)
And now second for AffjaxResponse a:
get :: forall e a
. Respondable a
=> URL
-> Aff
(ajax :: AJAX | e)
{ status :: StatusCode
, headers :: Array ResponseHeader
, response :: a
}
Related
If I have a record type:
type Rec_ab = { a :: String, b :: Int }
Can I get from it type which is effectfully extended with {c :: Boolean} : { a :: String, b :: Int, c :: Boolean }?
If I had a row, I could do it:
Row_ab = ( a :: String, b :: Int )
Rec_abc = { c :: Boolean | Row_ab }
but if I have a record Rec_ab how this should be solved? I'm not aware of the way of going from Record -> Row.
In general, you can't.
If you need that kind of extensibility, your approach with Row_ab is good enough, but another possible solution is to parametrize the record and then use the parameter to extend it:
type Rec_ab r = { a :: String, b :: Int | r }
type Rec_abc = Rec_ab ( c :: Boolean )
This also allows you to write functions that would work with both Rec_ab and Rec_abc:
add42 :: forall r. Rec_ab r -> Rec_ab r
add42 r = r { b = r.b + 42 }
data Foo a = Foo a
I can create an array of Exists https://github.com/purescript/purescript-exists
[(mkExists (Foo 0)), (mkExists (Foo "x"))]
How can I use type classes? I want to get ["0", "x"]
getStrings :: Array (Exists Foo) -> Array String
getStrings list = map (runExists get) list
where
get :: forall a. Show a => Foo a -> String
get (Foo a) = show a
No type class instance was found for
Prelude.Show _0
The instance head contains unknown type variables. Consider adding a
type annotation.
One option is to bundle up the show function in your definition of Foo, something like this:
import Prelude
import Data.Exists
data Foo a = Foo a (a -> String)
type FooE = Exists Foo
mkFooE :: forall a. (Show a) => a -> FooE
mkFooE a = mkExists (Foo a show)
getStrings :: Array FooE -> Array String
getStrings = map (runExists get)
where
get :: forall a. Foo a -> String
get (Foo a toString) = toString a
--
items :: Array FooE
items = [mkFooE 0, mkFooE 0.5, mkFooE "test"]
items' :: Array String
items' = getStrings items
I have the following code:
def nextOption(map : OptionMap, list: List[String]) : OptionMap = {
def isSwitch(s : String) = (s(0) == '-')
list match {
case Nil => map
case "--inputFile" :: value :: tail =>
nextOption(map ++ Map('input -> value.toString), tail)
case "--schemaFile" :: value :: tail =>
nextOption(map ++ Map('schema -> value.toString), tail)
case "--outputD" :: value :: tail =>
nextOption(map ++ Map('output -> value.toString), tail)
case "--delimiter" :: value :: tail =>
nextOption(map ++ Map('delimiter -> value.toString), tail)
case option :: tail => println("Unknown option "+option)
exit(1)
}
}
The only issue is I get "Cannot Resolve Symbol Exit" in intellij. I picked this code from a popular post about accepting input parameters and it doesnt look like anyone else is getting this issue.
exit used to be defined in Predef, meaning that it was always in scope. It is now defined in package scala.sys, so just do sys.exit(1).
It was deprecated in 2.9 and replaced with sys.exit.
Related question: Scala error function deprecated. What is the alternative?
I am using scodec: https://github.com/scodec/scodec to decode/encode a binary protocol.
I am struggling with a part of the spec where a "length" field is split into two parts by a "moreflag". The moreflag indicates if the length field needs more space.
Example:
Byte 1: identifier bits 8-7, moreFlag bit 6, length bits 5-0 // first length field filled with 0's if moreFlag is false
Byte 2: moreFlag bit 8, length bits 7-0
Byte 3: otherJunk bits 8-0
My problem is I want to encode/decode both of these length fields into a single case class field:
case class Header(totalLength: Int, otherJunk: Int)
I have tried a few different things, but nothing has worked out so far:
implicit val headerCodec: Codec[Header] = (
("identifier" | uint2) :~>:
("moreFlag" | bool).compact >>:~ { meta =>
if (meta.last) {
// more flag enabled, combine lengths somehow
("first length part" | uint(5)) :: ("moreFlag2DontCare" | uint(1) :~>: ("second length part - how to combine?" | uint(7)) :: ("otherJunk" | uint8)
}
else {
("first length part always 0s" | constant(bin"00000")) :: ("moreFlag2DontCare" | uint(1) :~>: ("fullLength" | uint(7)) :: ("otherJunk" | uint8)
}
}
).as[Header]
Am I on the right track here? Thanks!
One way to accomplish this is to use the predefined combinators to define the structure of the binary format -- not the combination logic. Then put the combination logic inside a function passed to xmap.
import scodec._
import bits._
import codecs._
import shapeless._
case class Header(totalLength: Int, otherJunk: Int)
object Header {
implicit val codec: Codec[Header] = {
type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
def to(header: Header): Struct = {
val lengthBits = uint(12).encodeValid(header.totalLength)
val more = !(lengthBits startsWith bin"00000")
0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
}
def from(struct: Struct): Header = struct match {
case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
val length =
if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
else uint(7).decodeValidValue(lowerLengthBits)
Header(length, otherJunk)
}
struct.xmap[Header](from, to)
}
}
Note that the upper and lower length bits are encoded as bits(5) and bits(7) and then manually combined in the from function and decoded. The decoding is safe, despite using the unsafe decodeValidValue, because the uint(12) codec is total on 12-bit inputs -- it is impossible for it to return a left.
However, the to function uses encodeValid, which is clearly unsafe -- e.g., Int.MaxValue will cause an exception. We can fix this with a slightly more complicated version, where the to function returns an Err \/ Struct, and we call widen instead of xmap:
object Header {
implicit val codec: Codec[Header] = {
type Struct = Int :: Boolean :: BitVector :: Boolean :: BitVector :: Int :: HNil
val struct: Codec[Struct] = ("identifier" | uint2) :: ("moreFlag" | bool) :: ("upper length bits" | codecs.bits(5)) :: ("moreFlag2" | bool) :: ("lower length bits" | codecs.bits(7)) :: ("other junk" | uint8)
def to(header: Header): Err \/ Struct = {
uint(12).encode(header.totalLength) map { lengthBits =>
val more = !(lengthBits startsWith bin"00000")
0 :: more :: lengthBits.take(5) :: false :: lengthBits.drop(5) :: header.otherJunk :: HNil
}
}
def from(struct: Struct): Header = struct match {
case id :: moreFlag :: upperLengthBits :: moreFlag2 :: lowerLengthBits :: otherJunk :: HNil =>
val length =
if (moreFlag) uint(12).decodeValidValue(upperLengthBits ++ lowerLengthBits)
else uint(7).decodeValidValue(lowerLengthBits)
Header(length, otherJunk)
}
struct.widen[Header](from, to)
}
}
I'm learning scala, and this question may be stupid, but... why?
For example, this is ok:
def matchList(ls: List[Int]): List[Int] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
matchList: (ls: List[Int])List[Int]
But function with type parameter does not compile:
def matchList[T](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}
<console>:10: error: type mismatch;
found : T
required: String
case a :: b :: rest => (a + b) :: rest
Why?
For any type T the operation T + T doesn't make any sense. (Do all types support +? No. Think of adding two dogs or two employees.)
In your case, the string concatenation operator is getting invoked (added via any2stringadd pimp), whose return type is (obviously) String. Hence the error message.
What you need is a way to specify that type T must support an operation where you combine two values of type T to yield a new value of type T. Scalaz's Semigroup fits the bill perfectly.
The following works:
def matchList[T : Semigroup](ls: List[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => (a |+| b) :: rest // |+| is a generic 'combining' operator
case _ => ls
}
I think the problem lies in (a + b), the only universal usage of the + operator is string concatenation, so a and b must both be Strings (or automatically convertible to Strings) in order for that to be valid. Your parameterized type T isn't known to be a String, so it fails to compile.
In the second example, your a, b variables of declared type T are not convertible to String, which is the required argument type of +, inferred from your program (i.e. the view applied to the type of arguments of +in the absence of any other information).
In the first example, inference can guess the right + function to apply, considering it takes as arguments the type of elements of the list, and that thankfully, you have mentioned in the type declaration that the type of those elements is Int. Try typing
"1"+2
1 + 2
... in an REPL and see what Scala tries to do. Then read about views.
Now, I surmise that by using that type parameter T above, you are trying to write a function that works with any numerical type, aren't you ? In that case, you can work with the Numeric trait. I'll let you read up on implicits before suggesting the following:
def matchList[T](ls: List[T])(implicit n:Numeric[T]): List[T] = {
import n.mkNumericOps
ls match {
case 1 :: rest => rest
case a :: b :: rest => (a + b) :: rest
case _ => ls
}}
You get:
matchList(List(1,2,3))
res2: List[Int] = List(2, 3)
matchList(List(2,3,4))
res4: List[Int] = List(5, 4)
matchList(List(2.0,3.0,4.0))
res5: List[Double] = List(5.0, 4.0)
Without any import:
def matchList[T](ls: List[T])(implicit wrapper:Numeric[T]): List[T] = ls match {
case 1 :: rest => rest
case a :: b :: rest => wrapper.plus(a, b) :: rest
case _ => ls
}