I have a OTP - 19.3.6 environment.
I am trying to use a library that depends on OTP - 22.
So, I am trying to use and write compatibilities to use that library.
For eg. I ran into string:lowercase and unicode_util, issues, so I found a compat lib to get past those issues: https://github.com/benoitc/unicode_util_compat
Then I ran into maps:iterator and maps:next issues.
Based on my limited erlang understanding, I tried to write maps_compat.erl
I got past maps:iterator and maps:next issues.
However, I got this error where map_next is erts_internal.erl function:
Stacktrace =
** [{erlang,nif_error,[undefined],[]},
{maps_compat,map_next,3, [{file,"../apns_v2_otp_19.3.6/_build/default/lib/xxx/src/maps_compat.erl"}
from https://github.com/erlang/otp/blob/master/erts/preloaded/src/erts_internal.erl
%% return the next assoc in the iterator and a new iterator
-spec map_next(I, M, A) -> {K,V,NI} | list() when
I :: non_neg_integer(),
M :: map(),
K :: term(),
V :: term(),
A :: iterator | list(),
NI :: maps:iterator().
map_next(_I, _M, _A) ->
erlang:nif_error(undefined).
I modified the above function in my maps_compat.erl as
%% return the next assoc in the iterator and a new iterator
-spec map_next(I, M, A) -> {K,V,NI} | list() when
I :: non_neg_integer(),
M :: map(),
K :: term(),
V :: term(),
A :: iterator | list(),
NI :: iterator().
map_next(_I, _M, _A) ->
erlang:nif_error(undefined).
but it failed with the error above.
Can this issue be fixed?
If so, how can I fix this?
Is there a maps_compat library already such as unicode_util_compat?
Please help me resolve this issue.
As per suggestion in https://github.com/erlang/otp/issues/4595, I implemented this to not get this error anymore.
maps_iterator(Map) ->
maps:to_list(Map).
maps_next([{K,V} | T]) ->
{K, V, T};
maps_next([]) ->
none.
Related
I'm trying to define a greedy function
greedy :: ReadP a -> ReadP [a]
that parses a sequence of values, returning only the "maximal" sequences that cannot be extended any further. For example,
> readP_to_S (greedy (string "a" +++ string "ab")) "abaac"
[(["a"],"baac"),(["ab","a","a"],"c")]
I'm using a very simple and probably clumsy way. Just parse the values and see if they can be parsed any further; if so, then reapply the function again to get all the possible values and concat that with the previous ones, or else just return the value itself. However, there seems to be some type problems, below is my code.
import Text.ParserCombinators.ReadP
addpair :: a -> [([a],String)] -> [([a],String)]
addpair a [] = []
addpair a (c:cs) = (a : (fst c), snd c ) : (addpair a cs)
greedy :: ReadP a -> ReadP [a]
greedy ap = readS_to_P (\s ->
let list = readP_to_S ap s in
f list )
where
f :: [(a,String)] -> [([a],String)]
f ((value, str2):cs) =
case readP_to_S ap str2 of
[] -> ([value], str2) : (f cs)
_ -> (addpair value (readP_to_S (greedy ap) str2)) ++ (f cs)
The GHC processes the code and says that function "f" has type [(a1,String)] -> [([a1],String)] but greedy is ReadP a -> ReadP [a]. I wonder why it is so because I think their type should agree. It also really helps if anyone can come up with some clever and more elegant approach to define the function greedy(my approach is definitely way too redundant)
To fix the compilation error, you need to add the language extension
{-# LANGUAGE ScopedTypeVariables #-}
to your source file, or pass the corresponding flag into the compiler. You also need to change the type signature of greedy to
greedy :: forall a. ReadP a -> ReadP [a]
This is because your two a type variables are not actually the same; they're in different scopes. With the extension and the forall, they are treated as being the same variable, and your types unify properly. Even then, the code errors, because you don't have an exhaustive pattern match in your definition of f. If you add
f [] = []
then the code seems to work as intended.
In order to simplify your code, I took a look at the provided function munch, which is defined as:
munch :: (Char -> Bool) -> ReadP String
-- ^ Parses the first zero or more characters satisfying the predicate.
-- Always succeeds, exactly once having consumed all the characters
-- Hence NOT the same as (many (satisfy p))
munch p =
do s <- look
scan s
where
scan (c:cs) | p c = do _ <- get; s <- scan cs; return (c:s)
scan _ = do return ""
In that spirit, your code can be rewritten as:
greedy2 :: forall a. ReadP a -> ReadP [a]
greedy2 ap = do
-- look at the string
s <- look
-- try parsing it, but without do notation
case readP_to_S ap s of
-- if we failed, then return nothing
[] -> return []
-- if we parsed something, ignore it
(_:_) -> do
-- parse it again, but this time inside of the monad
x <- ap
-- recurse, greedily parsing again
xs <- greedy2 ap
-- and return the concatenated values
return (x:xs)
This does have the speed disadvantage of executing ap twice as often as needed; this may be too slow for your use case. I'm sure my code could be further rewritten to avoid that, but I'm not a ReadP expert.
I've written a simple parser using readP. it works, but I'm using it as a sort of validating parser, as input is manually written and sometimes deviates from norm. in order to correct the input, I'd like to know in which line my parser failed, so my question is:
how can I obtain a debugging message showing in which line of input my parser failed, like the ones shown in real world haskell (for Parsec)?
(I'm fairly new to haskell, btw.)
ReadP doesn't offer error-reporting capabilities. That's evident from the type of a ReadP parser:
newtype ReadP a = R (forall b . (a -> P b) -> P b)
data P a
= Get (Char -> P a)
| Look (String -> P a)
| Fail
| Result a (P a)
| Final [(a,String)] -- invariant: list is non-empty!
deriving Functor
You can see that the Fail constructor doesn't store any information.
You will need to use a different parser combinator library for that (or build your own).
I'm required to write my own tuple_to_list() function (yes, from the book) and came up with this in my erl file:
%% Our very own tuple_to_list function! %%
% First, the accumulator function
my_tuple_to_list_acc(T, L) -> [element(1, T) | L];
my_tuple_to_list_acc({}, L) -> L;
% Finally, the public face of the function
my_tuple_to_list(T) -> my_tuple_to_list_acc(T, []).
When I compile this, however, I get the following error in the shell:
28> c(lib_misc).
lib_misc.erl:34: head mismatch
lib_misc.erl:2: function my_tuple_to_list/1 undefined
error
I have no clue what "head mismatch" there is, and why is the function undefined (I've added it to the module export statement, though I doubt this has much to do with export statements)?
The other answer explains how to fix this, but not the reason. So: ; after a function definition clause means the next clause continues the definition, just like as for case and if branches. head mismatch means you have function clauses with different names and/or number of arguments in one definition. For the same reason, it is an error to have a clause ending with . followed by another clause with the same name and argument count.
Changing the order of the clauses is needed for a different reason, not because of the error. Clauses are always checked in order (again, same as for case and if) and your first clause already matches any two arguments. So the second would never be used.
Those errors mean that you didn't end definition of my_tuple_to_list_acc/2.
You should change order of first two code lines and add dot after them.
my_tuple_to_list_acc({}, L) -> L;
my_tuple_to_list_acc(T, L) -> [element(1, T) | L].
When you are interested in working tuple_to_list/1 implementation
1> T2L = fun (T) -> (fun F(_, 0, Acc) -> Acc; F(T, N, Acc) -> F(T, N-1, [element(N, T)|Acc]) end)(T, tuple_size(T), []) end.
#Fun<erl_eval.6.50752066>
2> T2L({}).
[]
3> T2L({a,b,c}).
[a,b,c]
Or in module
my_typle_to_list(_, 0, Acc) -> Acc;
my_typle_to_list(T, N, Acc) ->
my_typle_to_list(T, N-1, [element(N, T)|Acc]).
my_typle_to_list(T) ->
my_typle_to_list(T, tuple_size(T), []).
Note how I use decreasing index for tail recursive function.
Inspired from this question, I was curious to see how lists:reverse/2 is implemented in the source code inside lists.erl module.
I found out that there is no implementation for lists:reverse/2 inside lists.erl, but there is an implementation for lists:reverse/1 that uses lists:reverse/2:
reverse([] = L) ->
L;
reverse([_] = L) ->
L;
reverse([A, B]) ->
[B, A];
reverse([A, B | L]) ->
lists:reverse(L, [B, A]).
At the top of the file there are some lines that tells that lists:reverse/2 (and some other functions) are BIFs:
%%% BIFs
-export([keyfind/3, keymember/3, keysearch/3, member/2, reverse/2]).
...
%% Shadowed by erl_bif_types: lists:reverse/2
-spec reverse(List1, Tail) -> List2 when
List1 :: [T],
Tail :: term(),
List2 :: [T],
T :: term().
reverse(_, _) ->
erlang:nif_error(undef).
Question: First, I couldn't find the actual implementations of those BIFs. Where can I find them? Second, If someone also knows to explain why is it organized that way?
The lists BIFs are implemented in erts/emulator/beam/erl_bif_lists.c. Parts of heavily-used standard modules such as lists are implemented as BIFs for efficiency and performance.
I'm following Gentle introduction to Haskell tutorial and the code presented there seems to be broken. I need to understand whether it is so, or my seeing of the concept is wrong.
I am implementing parser for custom type:
data Tree a = Leaf a | Branch (Tree a) (Tree a)
printing function for convenience
showsTree :: Show a => Tree a -> String -> String
showsTree (Leaf x) = shows x
showsTree (Branch l r) = ('<':) . showsTree l . ('|':) . showsTree r . ('>':)
instance Show a => Show (Tree a) where
showsPrec _ x = showsTree x
this parser is fine but breaks when there are spaces
readsTree :: (Read a) => String -> [(Tree a, String)]
readsTree ('<':s) = [(Branch l r, u) | (l, '|':t) <- readsTree s,
(r, '>':u) <- readsTree t ]
readsTree s = [(Leaf x, t) | (x,t) <- reads s]
this one is said to be a better solution, but it does not work without spaces
readsTree_lex :: (Read a) => String -> [(Tree a, String)]
readsTree_lex s = [(Branch l r, x) | ("<", t) <- lex s,
(l, u) <- readsTree_lex t,
("|", v) <- lex u,
(r, w) <- readsTree_lex v,
(">", x) <- lex w ]
++
[(Leaf x, t) | (x, t) <- reads s ]
next I pick one of parsers to use with read
instance Read a => Read (Tree a) where
readsPrec _ s = readsTree s
then I load it in ghci using Leksah debug mode (this is unrelevant, I guess), and try to parse two strings:
read "<1|<2|3>>" :: Tree Int -- succeeds with readsTree
read "<1| <2|3> >" :: Tree Int -- succeeds with readsTree_lex
when lex encounters |<2... part of the former string, it splits onto ("|<", _). That does not match ("|", v) <- lex u part of parser and fails to complete parsing.
There are two questions arising:
how do I define parser that really ignores spaces, not requires them?
how can I define rules for splitting encountered literals with lex
speaking of second question -- it is asked more of curiousity as defining my own lexer seems to be more correct than defining rules of existing one.
lex splits into Haskell lexemes, skipping whitespace.
This means that since Haskell permits |< as a lexeme, lex will not split it into two lexemes, since that's not how it parses in Haskell.
You can only use lex in your parser if you're using the same (or similar) syntactic rules to Haskell.
If you want to ignore all whitespace (as opposed to making any whitespace equivalent to one space), it's much simpler and more efficient to first run filter (not.isSpace).
The answer to this seems to be a small gap between text of Gentle introduction to Haskell and its code samples, plus an error in sample code.
there should also be one more lexer, but there is no working example (satisfying my need) in codebase, so I written one. Please point out any flaw in it:
lexAll :: ReadS String
lexAll s = case lex s of
[("",_)] -> [] -- nothing to parse.
[(c, r)] -> if length c == 1 then [(c, r)] -- we will try to match
else [(c, r), ([head s], tail s)]-- not only as it was
any_else -> any_else -- parsed but also splitted
author sais:
Finally, the complete reader. This is not sensitive to white space as
were the previous versions. When you derive the Show class for a data
type the reader generated automatically is similar to this in style.
but lexAll should be used instead of lex (which seems to be said error):
readsTree' :: (Read a) => ReadS (Tree a)
readsTree' s = [(Branch l r, x) | ("<", t) <- lexAll s,
(l, u) <- readsTree' t,
("|", v) <- lexAll u,
(r, w) <- readsTree' v,
(">", x) <- lexAll w ]
++
[(Leaf x, t) | (x, t) <- reads s]