为什么将数据类型添加为类型声明的约束会导致匹配错误而不是更正确的错误?

时间:2015-09-21 03:48:17

标签: haskell typeclass

或者,换句话说,是否需要添加如下所述的约束?

工作代码,函数 f 的最小类型声明:

data ZeroPositive = Zero | Positive Int deriving Show
f :: [Int] -> [ZeroPositive]
f [] = []
f (0:xs) = Zero:(f xs)
f (x:xs) = (Positive x):(f xs)
main = putStrLn . show $ f [0,2]

结果:

[Zero,Positive 2]

破解代码,无用约束 ZeroPositive

data ZeroPositive = Zero | Positive Int deriving Show
f :: ZeroPositive => [Int] -> [ZeroPositive]
f [] = []
f (0:xs) = Zero:(f xs)
f (x:xs) = (Positive x):(f xs)
main = putStrLn . show $ f [0,2]

结果:

  99.hs:3:7:
  Couldn't match expected type `ZeroPositive' with actual type `[t0]'
  In the pattern: []
  In an equation for `f': f [] = []

  99.hs:3:12:
  Couldn't match expected type `[Int] -> [ZeroPositive]'
          with actual type `[a0]'
  In the expression: []
  In an equation for `f': f [] = []

  ...

  99.hs:6:32:
  Couldn't match expected type `ZeroPositive' with actual type `[t0]'
  In the first argument of `f', namely `[0, 2]'
  In the second argument of `($)', namely `f [0, 2]'
  In the expression: putStrLn . show $ f [0, 2]

2 个答案:

答案 0 :(得分:5)

应该是一个错误,因为ZeroPositive是一种数据类型,而不是一个类,因此不允许作为约束。

然而,你得到的奇怪的错误信息,是因为你使用的是具有a bug的旧GHC版本(如果我没记错的话, GHC 7.4 GHC 7.6,获得了ConstraintKinds扩展程序通常正常工作,因此在语法中的更多相同位置允许=>->,这使得=>->视为@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); selectUsers = new ArrayList<SelectUser>(); resolver = getContentResolver(); contacts_list = (ListView) findViewById(R.id.contacts_list); phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC"); LoadContact loadContact = new LoadContact(); loadContact.execute(); } class LoadContact extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Void doInBackground(Void... voids) { // Get Contact list from Phone if (phones != null) { Log.e("count", "" + phones.getCount()); if (phones.getCount() == 0) { } while (phones.moveToNext()) { String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)); String selected_name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); String EmailAddr = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); String image_thumb = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI)); try { if (image_thumb != null) { bit_thumb = MediaStore.Images.Media.getBitmap(resolver, Uri.parse(image_thumb)); } else { Log.e("No Image Thumb", "--------------"); } } catch (IOException e) { e.printStackTrace(); } SelectUser selectUser = new SelectUser(); selectUser.setThumb(bit_thumb); selectUser.setName(selected_name); selectUser.setPhone(phoneNumber); Cursor emailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[] { id }, null); while (emailCursor.moveToNext()) { emails = emailCursor.getString(emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); System.out.println("Email : " + emails); selectUser.setEmail(emails); } emailCursor.close(); selectUser.setCheckedBox(false); selectUsers.add(selectUser); } } else { Log.e("Cursor close 1", "----------------"); } //phones.close(); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); adapter = new SelectUserAdapter(selectUsers, MainActivity.this); contacts_list.setAdapter(adapter); // Select item on listclick contacts_list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Log.e("search", "here---------------- listener"); data = selectUsers.get(i); String phoneNumber = data.getPhone(); String email = data.getEmail(); String name = data.getName(); Intent i1 = new Intent(MainActivity.this, SingleContact.class); i1.putExtra("name", name); i1.putExtra("phone_number", phoneNumber); i1.putExtra("email", email); startActivity(i1); } }); contacts_list.setFastScrollEnabled(true); } } 将实际数据类型而不是约束放在其左侧。

答案 1 :(得分:4)

我不明白你得到的错误; ØrjanJohansen的回答给出了合理的解释。真正的问题是:只要类型签名指示a => ba就应该是约束。在标准Haskell中,这意味着a看起来像C t,其中C是类的名称,t是类型变量。在格拉斯哥哈斯克尔,约束可以更丰富。但是,在任何情况下,数据和约束都是完全不同的类型(在一般意义上它们具有不同的类型),因此您根本无法将数据类型用作上下文。